JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> {
return 0;
}
// let's just advance ptr to end
int origPtr = _inputPtr;
out.write(_inputBuffer, origPtr, count);
return count;
}
@Override
public Object getInputSource() {
return _inputStream;
}
/*
/**********************************************************
/* Overrides, low-level reading
/**********************************************************
*/
@Override
protected final boolean loadMore() throws IOException
{
final int bufSize = _inputEnd;
_currInputProcessed += _inputEnd;
_currInputRowStart -= _inputEnd;
// 26-Nov-2015, tatu: Since name-offset requires it too, must offset
// this increase to avoid "moving" name-offset, resulting most likely
// in negative value, which is fine as combine value remains unchanged.
_nameStartOffset -= bufSize;
if (_inputStream != null) {
int space = _inputBuffer.length;
if (space == 0) { // only occurs when we've been closed
return false;
}
int count = _inputStream.read(_inputBuffer, 0, space);
if (count > 0) {
_inputPtr = 0;
_inputEnd = count;
return true;
}
// End of input
_closeInput();
// Should never return 0, so let's fail
if (count == 0) {
throw new IOException("InputStream.read() returned 0 characters when trying to read "+_inputBuffer.length+" bytes");
}
}
return false;
}
/**
* Helper method that will try to load at least specified number bytes in
* input buffer, possible moving existing data around if necessary
*/
protected final boolean _loadToHaveAtLeast(int minAvailable) throws IOException
{
// No input stream, no leading (either we are closed, or have non-stream input source)
if (_inputStream == null) {
return false;
}
// Need to move remaining data in front?
int amount = _inputEnd - _inputPtr;
if (amount > 0 && _inputPtr > 0) {
final int ptr = _inputPtr;
_currInputProcessed += ptr;
_currInputRowStart -= ptr;
// 26-Nov-2015, tatu: Since name-offset requires it too
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>, must offset
// (note: probably has little effect here but just in case)
_nameStartOffset -= ptr;
System.arraycopy(_inputBuffer, ptr, _inputBuffer, 0, amount);
_inputEnd = amount;
} else {
_inputEnd = 0;
}
_inputPtr = 0;
while (_inputEnd < minAvailable) {
int count = _inputStream.read(_inputBuffer, _inputEnd, _inputBuffer.length - _inputEnd);
if (count < 1) {
// End of input
_closeInput();
// Should never return 0, so let's fail
if (count == 0) {
throw new IOException("InputStream.read() returned 0 characters when trying to read "+amount+" bytes");
}
return false;
}
_inputEnd += count;
}
return true;
}
@Override
protected void _closeInput() throws IOException
{
/* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
* on the underlying InputStream, unless we "own" it, or auto-closing
* feature is enabled.
*/
if (_inputStream != null) {
if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) {
_inputStream.close();
}
_inputStream = null;
}
}
/**
* Method called to release internal buffers owned by the base
* reader. This may be called along with {@link #_closeInput} (for
* example, when explicitly closing this reader instance), or
* separately (if need be).
*/
@Override
protected void _releaseBuffers() throws IOException
{
super._releaseBuffers();
// Merge found symbols, if any:
_symbols.release();
if (_bufferRecyclable) {
byte[] buf = _inputBuffer;
if (buf != null) {
/* 21-Nov-2014, tatu: Let's not set it to null; this way should
* get slightly more meaningful error messages in case someone
* closes parser indirectly, without realizing.
*/
_inputBuffer = ByteArrayBuilder.NO_BYTES;
_ioContext.releaseReadIOBuffer(buf);
}
}
}
/*
/********************************************************
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>**
/* Public API, data access
/**********************************************************
*/
@Override
public String getText() throws IOException
{
if (_currToken == JsonToken.VALUE_STRING) {
if (_tokenIncomplete) {
_tokenIncomplete = false;
return _finishAndReturnString(); // only strings can be incomplete
}
return _textBuffer.contentsAsString();
}
return _getText2(_currToken);
}
// // // Let's override default impls for improved performance
// @since 2.1
@Override
public String getValueAsString() throws IOException
{
if (_currToken == JsonToken.VALUE_STRING) {
if (_tokenIncomplete) {
_tokenIncomplete = false;
return _finishAndReturnString(); // only strings can be incomplete
}
return _textBuffer.contentsAsString();
}
if (_currToken == JsonToken.FIELD_NAME) {
return getCurrentName();
}
return super.getValueAsString(null);
}
// @since 2.1
@Override
public String getValueAsString(String defValue) throws IOException
{
if (_currToken == JsonToken.VALUE_STRING) {
if (_tokenIncomplete) {
_tokenIncomplete = false;
return _finishAndReturnString(); // only strings can be incomplete
}
return _textBuffer.contentsAsString();
}
if (_currToken == JsonToken.FIELD_NAME) {
return getCurrentName();
}
return super.getValueAsString(defValue);
}
// since 2.6
@Override
public int getValueAsInt() throws IOException
{
JsonToken t = _currToken;
if ((t == JsonToken.VALUE_NUMBER_INT) || (t == JsonToken.VALUE_NUMBER_FLOAT)) {
// inlined 'getIntValue()'
if ((_numTypesValid & NR_INT) == 0) {
if (_numTypesValid == NR_UNKNOWN) {
return _parseIntValue();
}
if ((_numTypesValid & NR_INT) == 0) {
convertNumberToInt();
}
}
return _numberInt;
}
return super.getValueAsInt(0);
}
// since 2.6
@Override
public int getValueAsInt(int defValue) throws IOException
{
JsonToken t = _currToken;
if ((t == JsonToken.VALUE_NUMBER_INT) || (t
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> == JsonToken.VALUE_NUMBER_FLOAT)) {
// inlined 'getIntValue()'
if ((_numTypesValid & NR_INT) == 0) {
if (_numTypesValid == NR_UNKNOWN) {
return _parseIntValue();
}
if ((_numTypesValid & NR_INT) == 0) {
convertNumberToInt();
}
}
return _numberInt;
}
return super.getValueAsInt(defValue);
}
protected final String _getText2(JsonToken t)
{
if (t == null) {
return null;
}
switch (t.id()) {
case ID_FIELD_NAME:
return _parsingContext.getCurrentName();
case ID_STRING:
// fall through
case ID_NUMBER_INT:
case ID_NUMBER_FLOAT:
return _textBuffer.contentsAsString();
default:
return t.asString();
}
}
@Override
public char[] getTextCharacters() throws IOException
{
if (_currToken != null) { // null only before/after document
switch (_currToken.id()) {
case ID_FIELD_NAME:
if (!_nameCopied) {
String name = _parsingContext.getCurrentName();
int nameLen = name.length();
if (_nameCopyBuffer == null) {
_nameCopyBuffer = _ioContext.allocNameCopyBuffer(nameLen);
} else if (_nameCopyBuffer.length < nameLen) {
_nameCopyBuffer = new char[nameLen];
}
name.getChars(0, nameLen, _nameCopyBuffer, 0);
_nameCopied = true;
}
return _nameCopyBuffer;
case ID_STRING:
if (_tokenIncomplete) {
_tokenIncomplete = false;
_finishString(); // only strings can be incomplete
}
// fall through
case ID_NUMBER_INT:
case ID_NUMBER_FLOAT:
return _textBuffer.getTextBuffer();
default:
return _currToken.asCharArray();
}
}
return null;
}
@Override
public int getTextLength() throws IOException
{
if (_currToken != null) { // null only before/after document
switch (_currToken.id()) {
case ID_FIELD_NAME:
return _parsingContext.getCurrentName().length();
case ID_STRING:
if (_tokenIncomplete) {
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> _tokenIncomplete = false;
_finishString(); // only strings can be incomplete
}
// fall through
case ID_NUMBER_INT:
case ID_NUMBER_FLOAT:
return _textBuffer.size();
default:
return _currToken.asCharArray().length;
}
}
return 0;
}
@Override
public int getTextOffset() throws IOException
{
// Most have offset of 0, only some may have other values:
if (_currToken != null) {
switch (_currToken.id()) {
case ID_FIELD_NAME:
return 0;
case ID_STRING:
if (_tokenIncomplete) {
_tokenIncomplete = false;
_finishString(); // only strings can be incomplete
}
// fall through
case ID_NUMBER_INT:
case ID_NUMBER_FLOAT:
return _textBuffer.getTextOffset();
default:
}
}
return 0;
}
@Override
public byte[] getBinaryValue(Base64Variant b64variant) throws IOException
{
if (_currToken != JsonToken.VALUE_STRING &&
(_currToken != JsonToken.VALUE_EMBEDDED_OBJECT || _binaryValue == null)) {
_reportError("Current token ("+_currToken+") not VALUE_STRING or VALUE_EMBEDDED_OBJECT, can not access as binary");
}
/* To ensure that we won't see inconsistent data, better clear up
* state...
*/
if (_tokenIncomplete) {
try {
_binaryValue = _decodeBase64(b64variant);
} catch (IllegalArgumentException iae) {
throw _constructError("Failed to decode VALUE_STRING as base64 ("+b64variant+"): "+iae.getMessage());
}
/* let's clear incomplete only now; allows for accessing other
* textual content in error cases
*/
_tokenIncomplete = false;
} else { // may actually require conversion...
if (_binaryValue == null) {
@SuppressWarnings("resource")
ByteArrayBuilder builder = _getByteArrayBuilder();
_decodeBase64(getText(), builder, b64variant);
_binaryValue = builder.toByteArray();
}
}
return _binaryValue;
}
@Override
public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException
{
// if we have already
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> read the token, just use whatever we may have
if (!_tokenIncomplete || _currToken != JsonToken.VALUE_STRING) {
byte[] b = getBinaryValue(b64variant);
out.write(b);
return b.length;
}
// otherwise do "real" incremental parsing...
byte[] buf = _ioContext.allocBase64Buffer();
try {
return _readBinary(b64variant, out, buf);
} finally {
_ioContext.releaseBase64Buffer(buf);
}
}
protected int _readBinary(Base64Variant b64variant, OutputStream out,
byte[] buffer) throws IOException
{
int outputPtr = 0;
final int outputEnd = buffer.length - 3;
int outputCount = 0;
while (true) {
// first, we'll skip preceding white space, if any
int ch;
do {
if (_inputPtr >= _inputEnd) {
loadMoreGuaranteed();
}
ch = (int) _inputBuffer[_inputPtr++] & 0xFF;
} while (ch <= INT_SPACE);
int bits = b64variant.decodeBase64Char(ch);
if (bits < 0) { // reached the end, fair and square?
if (ch == INT_QUOTE) {
break;
}
bits = _decodeBase64Escape(b64variant, ch, 0);
if (bits < 0) { // white space to skip
continue;
}
}
// enough room? If not, flush
if (outputPtr > outputEnd) {
outputCount += outputPtr;
out.write(buffer, 0, outputPtr);
outputPtr = 0;
}
int decodedData = bits;
// then second base64 char; can't get padding yet, nor ws
if (_inputPtr >= _inputEnd) {
loadMoreGuaranteed();
}
ch = _inputBuffer[_inputPtr++] & 0xFF;
bits = b64variant.decodeBase64Char(ch);
if (bits < 0) {
bits = _decodeBase64Escape(b64variant, ch, 1);
}
decodedData = (decodedData << 6) | bits;
// third base64 char; can be padding, but
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> _reportUnexpectedChar(i, "was expecting comma to separate "+_parsingContext.getTypeDesc()+" entries");
}
i = _skipWS();
}
if (!_parsingContext.inObject()) {
_updateLocation();
_nextTokenNotInObject(i);
return false;
}
// // // This part differs, name parsing
_updateNameLocation();
if (i == INT_QUOTE) {
// when doing literal match, must consider escaping:
byte[] nameBytes = str.asQuotedUTF8();
final int len = nameBytes.length;
// 22-May-2014, tatu: Actually, let's require 4 more bytes for faster skipping
// of colon that follows name
if ((_inputPtr + len + 4) < _inputEnd) { // maybe...
// first check length match by
final int end = _inputPtr+len;
if (_inputBuffer[end] == INT_QUOTE) {
int offset = 0;
int ptr = _inputPtr;
while (true) {
if (ptr == end) { // yes, match!
_parsingContext.setCurrentName(str.getValue());
i = _skipColonFast(ptr+1);
_isNextTokenNameYes(i);
return true;
}
if (nameBytes[offset] != _inputBuffer[ptr]) {
break;
}
++offset;
++ptr;
}
}
}
}
return _isNextTokenNameMaybe(i, str);
}
@Override
public String nextFieldName() throws IOException
{
// // // Note: this is almost a verbatim copy of nextToken()
_numTypesValid = NR_UNKNOWN;
if (_currToken == JsonToken.FIELD_NAME) {
_nextAfterName();
return null;
}
if (_tokenIncomplete) {
_skipString();
}
int i = _skipWSOrEnd();
if (i < 0) {
close();
_currToken = null;
return null;
}
_binaryValue = null;
if (i == INT_RBRACKET) {
_updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_ARRAY;
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> }
@Override
public String nextTextValue() throws IOException
{
// two distinct cases; either got name and we know next type, or 'other'
if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
_currToken = t;
if (t == JsonToken.VALUE_STRING) {
if (_tokenIncomplete) {
_tokenIncomplete = false;
return _finishAndReturnString();
}
return _textBuffer.contentsAsString();
}
if (t == JsonToken.START_ARRAY) {
_parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
} else if (t == JsonToken.START_OBJECT) {
_parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
}
return null;
}
// !!! TODO: optimize this case as well
return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
}
@Override
public int nextIntValue(int defaultValue) throws IOException
{
// two distinct cases; either got name and we know next type, or 'other'
if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
_currToken = t;
if (t == JsonToken.VALUE_NUMBER_INT) {
return getIntValue();
}
if (t == JsonToken.START_ARRAY) {
_parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
} else if (t == JsonToken.START_OBJECT) {
_parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
}
return defaultValue;
}
// !!! TODO: optimize this case as well
return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
}
@Override
public long nextLongValue(long defaultValue) throws IOException
{
// two distinct cases; either got name and we know next type, or 'other'
if (_currToken == JsonToken.FIELD_NAME) { //
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> The basic rule is that if the number
* has no fractional or exponential part, it is an integer; otherwise
* a floating point number.
*<p>
* Because much of input has to be processed in any case, no partial
* parsing is done: all input text will be stored for further
* processing. However, actual numeric value conversion will be
* deferred, since it is usually the most complicated and costliest
* part of processing.
*/
protected JsonToken _parsePosNumber(int c) throws IOException
{
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
// One special case: if first char is 0, must not be followed by a digit
if (c == INT_0) {
c = _verifyNoLeadingZeroes();
}
// Ok: we can first just add digit we saw first:
outBuf[0] = (char) c;
int intLen = 1;
int outPtr = 1;
// And then figure out how far we can read without further checks
// for either input or output
int end = _inputPtr + outBuf.length - 1; // 1 == outPtr
if (end > _inputEnd) {
end = _inputEnd;
}
// With this, we have a nice and tight loop:
while (true) {
if (_inputPtr >= end) { // split across boundary, offline
return _parseNumber2(outBuf, outPtr, false, intLen);
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break;
}
++intLen;
outBuf[outPtr++] = (char) c;
}
if (c == '.' || c == 'e' || c == 'E') {
return _parseFloat(outBuf, outPtr, c, false, intLen);
}
--_inputPtr; // to push back trailing char (comma etc)
_textBuffer.setCurrentLength(outPtr);
// As per #105, need separating space between root values; check here
if (_parsingContext.inRoot()) {
_verifyRootSpace(c);
}
// And there we have it!
return resetInt(false, intLen);
}
protected JsonToken _parseNegNumber()
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> throws IOException
{
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
int outPtr = 0;
// Need to prepend sign?
outBuf[outPtr++] = '-';
// Must have something after sign too
if (_inputPtr >= _inputEnd) {
loadMoreGuaranteed();
}
int c = (int) _inputBuffer[_inputPtr++] & 0xFF;
// Note: must be followed by a digit
if (c < INT_0 || c > INT_9) {
return _handleInvalidNumberStart(c, true);
}
// One special case: if first char is 0, must not be followed by a digit
if (c == INT_0) {
c = _verifyNoLeadingZeroes();
}
// Ok: we can first just add digit we saw first:
outBuf[outPtr++] = (char) c;
int intLen = 1;
// And then figure out how far we can read without further checks
// for either input or output
int end = _inputPtr + outBuf.length - outPtr;
if (end > _inputEnd) {
end = _inputEnd;
}
// With this, we have a nice and tight loop:
while (true) {
if (_inputPtr >= end) {
// Long enough to be split across boundary, so:
return _parseNumber2(outBuf, outPtr, true, intLen);
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break;
}
++intLen;
outBuf[outPtr++] = (char) c;
}
if (c == '.' || c == 'e' || c == 'E') {
return _parseFloat(outBuf, outPtr, c, true, intLen);
}
--_inputPtr; // to push back trailing char (comma etc)
_textBuffer.setCurrentLength(outPtr);
// As per #105, need separating space between root values; check here
if (_parsingContext.inRoot()) {
_verifyRootSpace(c);
}
// And there we have it!
return resetInt(true, intLen);
}
/**
* Method called to handle parsing when input is split across buffer boundary
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
* (or output is longer than segment used to store it)
*/
private final JsonToken _parseNumber2(char[] outBuf, int outPtr, boolean negative,
int intPartLength) throws IOException
{
// Ok, parse the rest
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
_textBuffer.setCurrentLength(outPtr);
return resetInt(negative, intPartLength);
}
int c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c > INT_9 || c < INT_0) {
if (c == INT_PERIOD || c == INT_e || c == INT_E) {
return _parseFloat(outBuf, outPtr, c, negative, intPartLength);
}
break;
}
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
outBuf[outPtr++] = (char) c;
++intPartLength;
}
--_inputPtr; // to push back trailing char (comma etc)
_textBuffer.setCurrentLength(outPtr);
// As per #105, need separating space between root values; check here
if (_parsingContext.inRoot()) {
_verifyRootSpace(_inputBuffer[_inputPtr++] & 0xFF);
}
// And there we have it!
return resetInt(negative, intPartLength);
}
/**
* Method called when we have seen one zero, and want to ensure
* it is not followed by another
*/
private final int _verifyNoLeadingZeroes() throws IOException
{
// Ok to have plain "0"
if (_inputPtr >= _inputEnd && !loadMore()) {
return INT_0;
}
int ch = _inputBuffer[_inputPtr] & 0xFF;
// if not followed by a number (probably '.'); return zero as is, to be included
if (ch < INT_0 || ch > INT_9) {
return INT_0;
}
// [JACKSON-358]: we may want to allow them, after all...
if (!isEnabled(Feature.ALLOW_NUMERIC_LEADING_ZEROS)) {
reportInvalidNumber("Leading zeroes not allowed");
}
// if so
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>, just need to skip either all zeroes (if followed by number); or all but one (if non-number)
++_inputPtr; // Leading zero to be skipped
if (ch == INT_0) {
while (_inputPtr < _inputEnd || loadMore()) {
ch = _inputBuffer[_inputPtr] & 0xFF;
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
outBuf[outPtr++] = (char) c;
}
// must be followed by sequence of ints, one minimum
if (fractLen == 0) {
reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
}
}
int expLen = 0;
if (c == INT_e || c == INT_E) { // exponent?
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
outBuf[outPtr++] = (char) c;
// Not optional, can require that we get one more char
if (_inputPtr >= _inputEnd) {
loadMoreGuaranteed();
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
// Sign indicator?
if (c == '-' || c == '+') {
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
outBuf[outPtr++] = (char) c;
// Likewise, non optional:
if (_inputPtr >= _inputEnd) {
loadMoreGuaranteed();
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
}
exp_loop:
while (c <= INT_9 && c >= INT_0) {
++expLen;
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
outBuf[outPtr++] = (char) c;
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break exp_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> }
// must be followed by sequence of ints, one minimum
if (expLen == 0) {
reportUnexpectedNumberChar(c, "Exponent indicator not followed by a digit");
}
}
// Ok; unless we hit end-of-input, need to push last char read back
if (!eof) {
--_inputPtr;
// As per [core#105], need separating space between root values; check here
if (_parsingContext.inRoot()) {
_verifyRootSpace(c);
}
}
_textBuffer.setCurrentLength(outPtr);
// And there we have it!
return resetFloat(negative, integerPartLength, fractLen, expLen);
}
/**
* Method called to ensure that a root-value is followed by a space
* token.
*<p>
* NOTE: caller MUST ensure there is at least one character available;
* and that input pointer is AT given char (not past)
*/
private final void _verifyRootSpace(int ch) throws IOException
{
// caller had pushed it back, before calling; reset
++_inputPtr;
// TODO? Handle UTF-8 char decoding for error reporting
switch (ch) {
case ' ':
case '\t':
return;
case '\r':
_skipCR();
return;
case '\n':
++_currInputRow;
_currInputRowStart = _inputPtr;
return;
}
_reportMissingRootWS(ch);
}
/*
/**********************************************************
/* Internal methods, secondary parsing
/**********************************************************
*/
protected final String _parseName(int i) throws IOException
{
if (i != INT_QUOTE) {
return _handleOddName(i);
}
// First: can we optimize out bounds checks?
if ((_inputPtr + 13) > _inputEnd) { // Need up to 12 chars, plus one trailing (quote)
return slowParseName();
}
// If so, can also unroll loops nicely
/* 25-Nov-2008, tatu: This may seem weird, but here we do
* NOT want to worry about UTF-8 decoding. Rather, we'll
* assume that part is ok (if not it will get caught
* later on), and just handle quotes and backslashes here.
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> 0xFF;
if (codes[i] != 0) {
if (i == INT_QUOTE) {
return findName(_quadBuffer, qlen, q, 3);
}
return parseEscapedName(_quadBuffer, qlen, q, i, 3);
}
q = (q << 8) | i;
i = input[_inputPtr++] & 0xFF;
if (codes[i] != 0) {
if (i == INT_QUOTE) {
return findName(_quadBuffer, qlen, q, 4);
}
return parseEscapedName(_quadBuffer, qlen, q, i, 4);
}
// Nope, no end in sight. Need to grow quad array etc
if (qlen >= _quadBuffer.length) {
_quadBuffer = growArrayBy(_quadBuffer, qlen);
}
_quadBuffer[qlen++] = q;
q = i;
}
/* Let's offline if we hit buffer boundary (otherwise would
* need to [try to] align input, which is bit complicated
* and may not always be possible)
*/
return parseEscapedName(_quadBuffer, qlen, 0, q, 0);
}
/**
* Method called when not even first 8 bytes are guaranteed
* to come consecutively. Happens rarely, so this is offlined;
* plus we'll also do full checks for escaping etc.
*/
protected String slowParseName() throws IOException
{
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
_reportInvalidEOF(": was expecting closing '\"' for name");
}
}
int i = _inputBuffer[_inputPtr++] & 0xFF;
if (i == INT_QUOTE) { // special case, ""
return "";
}
return parseEscapedName(_quadBuffer, 0, 0, i, 0);
}
private final String parseName(int q1, int ch, int lastQuadBytes) throws IOException {
return parseEscapedName(_quadBuffer, 0, q1, ch, lastQuadBytes);
}
private final String parseName(int q1, int q2, int ch, int lastQuadBytes) throws IOException {
_quadBuffer[0] =
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> q1;
return parseEscapedName(_quadBuffer, 1, q2, ch, lastQuadBytes);
}
private final String parseName(int q1, int q2, int q3, int ch, int lastQuadBytes) throws IOException {
_quadBuffer[0] = q1;
_quadBuffer[1] = q2;
return parseEscapedName(_quadBuffer, 2, q3, ch, lastQuadBytes);
}
/**
* Slower parsing method which is generally branched to when
* an escape sequence is detected (or alternatively for long
* names, one crossing input buffer boundary).
* Needs to be able to handle more exceptional cases, gets slower,
* and hance is offlined to a separate method.
*/
protected final String parseEscapedName(int[] quads, int qlen, int currQuad, int ch,
int currQuadBytes) throws IOException
{
/* 25-Nov-2008, tatu: This may seem weird, but here we do not want to worry about
* UTF-8 decoding yet. Rather, we'll assume that part is ok (if not it will get
* caught later on), and just handle quotes and backslashes here.
*/
final int[] codes = _icLatin1;
while (true) {
if (codes[ch] != 0) {
if (ch == INT_QUOTE) { // we are done
break;
}
// Unquoted white space?
if (ch != INT_BACKSLASH) {
// As per [JACKSON-208], call can now return:
_throwUnquotedSpace(ch, "name");
} else {
// Nope, escape sequence
ch = _decodeEscaped();
}
/* Oh crap. May need to UTF-8 (re-)encode it, if it's
* beyond 7-bit ascii. Gets pretty messy.
* If this happens often, may want to use different name
* canonicalization to avoid these hits.
*/
if (ch > 127) {
// Ok, we'll need room for first byte right away
if (currQuadBytes >= 4) {
if (qlen >= quads.length) {
_quadBuffer = quads = growArrayBy(quads,
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> quads.length);
}
quads[qlen++] = currQuad;
currQuad = 0;
currQuadBytes = 0;
}
if (ch < 0x800) { // 2-byte
currQuad = (currQuad << 8) | (0xc0 | (ch >> 6));
++currQuadBytes;
// Second byte gets output below:
} else { // 3 bytes; no need to worry about surrogates here
currQuad = (currQuad << 8) | (0xe0 | (ch >> 12));
++currQuadBytes;
// need room for middle byte?
if (currQuadBytes >= 4) {
if (qlen >= quads.length) {
_quadBuffer = quads = growArrayBy(quads, quads.length);
}
quads[qlen++] = currQuad;
currQuad = 0;
currQuadBytes = 0;
}
currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f));
++currQuadBytes;
}
// And same last byte in both cases, gets output below:
ch = 0x80 | (ch & 0x3f);
}
}
// Ok, we have one more byte to add at any rate:
if (currQuadBytes < 4) {
++currQuadBytes;
currQuad = (currQuad << 8) | ch;
} else {
if (qlen >= quads.length) {
_quadBuffer = quads = growArrayBy(quads, quads.length);
}
quads[qlen++] = currQuad;
currQuad = ch;
currQuadBytes = 1;
}
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
_reportInvalidEOF(" in field name");
}
}
ch = _inputBuffer[_inputPtr++] & 0xFF;
}
if (currQuadBytes > 0) {
if (qlen >= quads.length) {
_quadBuffer = quads = growArrayBy(quads, quads.length);
}
quads[qlen++] = pad(currQuad, currQuadBytes);
}
String name = _symbols
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>.findName(quads, qlen);
if (name == null) {
name = addName(quads, qlen, currQuadBytes);
}
return name;
}
/**
* Method called when we see non-white space character other
* than double quote, when expecting a field name.
* In standard mode will just throw an exception; but
* in non-standard modes may be able to parse name.
*/
protected String _handleOddName(int ch) throws IOException
{
// [JACKSON-173]: allow single quotes
if (ch == '\'' && isEnabled(Feature.ALLOW_SINGLE_QUOTES)) {
return _parseAposName();
}
// [JACKSON-69]: allow unquoted names if feature enabled:
if (!isEnabled(Feature.ALLOW_UNQUOTED_FIELD_NAMES)) {
char c = (char) _decodeCharForError(ch);
_reportUnexpectedChar(c, "was expecting double-quote to start field name");
}
/* Also: note that although we use a different table here,
* it does NOT handle UTF-8 decoding. It'll just pass those
* high-bit codes as acceptable for later decoding.
*/
final int[] codes = CharTypes.getInputCodeUtf8JsNames();
// Also: must start with a valid character...
if (codes[ch] != 0) {
_reportUnexpectedChar(ch, "was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name");
}
/* Ok, now; instead of ultra-optimizing parsing here (as with
* regular JSON names), let's just use the generic "slow"
* variant. Can measure its impact later on if need be
*/
int[] quads = _quadBuffer;
int qlen = 0;
int currQuad = 0;
int currQuadBytes = 0;
while (true) {
// Ok, we have one more byte to add at any rate:
if (currQuadBytes < 4) {
++currQuadBytes;
currQuad = (currQuad << 8) | ch;
} else {
if (qlen >= quads.length) {
_quadBuffer = quads = growArrayBy(quads, quads.length);
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> quads[qlen++] = currQuad;
currQuad = ch;
currQuadBytes = 1;
}
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
_reportInvalidEOF(" in field name");
}
}
ch = _inputBuffer[_inputPtr] & 0xFF;
if (codes[ch] != 0) {
break;
}
++_inputPtr;
}
if (currQuadBytes > 0) {
if (qlen >= quads.length) {
_quadBuffer = quads = growArrayBy(quads, quads.length);
}
quads[qlen++] = currQuad;
}
String name = _symbols.findName(quads, qlen);
if (name == null) {
name = addName(quads, qlen, currQuadBytes);
}
return name;
}
/* Parsing to support [JACKSON-173]. Plenty of duplicated code;
* main reason being to try to avoid slowing down fast path
* for valid JSON -- more alternatives, more code, generally
* bit slower execution.
*/
protected String _parseAposName() throws IOException
{
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
_reportInvalidEOF(": was expecting closing '\'' for name");
}
}
int ch = _inputBuffer[_inputPtr++] & 0xFF;
if (ch == '\'') { // special case, ''
return "";
}
int[] quads = _quadBuffer;
int qlen = 0;
int currQuad = 0;
int currQuadBytes = 0;
// Copied from parseEscapedFieldName, with minor mods:
final int[] codes = _icLatin1;
while (true) {
if (ch == '\'') {
break;
}
// additional check to skip handling of double-quotes
if (ch != '"' && codes[ch] != 0) {
if (ch != '\\') {
// Unquoted white space?
// As per [JACKSON-208], call can now return:
_throwUnquotedSpace(ch, "name");
} else {
// Nope, escape sequence
ch = _decodeEscaped();
}
/* Oh crap. May need
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> to UTF-8 (re-)encode it, if it's
* beyond 7-bit ascii. Gets pretty messy.
* If this happens often, may want to use different name
* canonicalization to avoid these hits.
*/
if (ch > 127) {
// Ok, we'll need room for first byte right away
if (currQuadBytes >= 4) {
if (qlen >= quads.length) {
_quadBuffer = quads = growArrayBy(quads, quads.length);
}
quads[qlen++] = currQuad;
currQuad = 0;
currQuadBytes = 0;
}
if (ch < 0x800) { // 2-byte
currQuad = (currQuad << 8) | (0xc0 | (ch >> 6));
++currQuadBytes;
// Second byte gets output below:
} else { // 3 bytes; no need to worry about surrogates here
currQuad = (currQuad << 8) | (0xe0 | (ch >> 12));
++currQuadBytes;
// need room for middle byte?
if (currQuadBytes >= 4) {
if (qlen >= quads.length) {
_quadBuffer = quads = growArrayBy(quads, quads.length);
}
quads[qlen++] = currQuad;
currQuad = 0;
currQuadBytes = 0;
}
currQuad = (currQuad << 8) | (0x80 | ((ch >> 6) & 0x3f));
++currQuadBytes;
}
// And same last byte in both cases, gets output below:
ch = 0x80 | (ch & 0x3f);
}
}
// Ok, we have one more byte to add at any rate:
if (currQuadBytes < 4) {
++currQuadBytes;
currQuad = (currQuad << 8) | ch;
} else {
if (qlen >= quads.length) {
_quadBuffer = quads = growArrayBy(quads, quads.length);
}
quads[qlen++] = currQuad;
currQuad = ch;
currQuadBytes = 1;
}
if (_inputPtr >=
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> _inputEnd) {
if (!loadMore()) {
_reportInvalidEOF(" in field name");
}
}
ch = _inputBuffer[_inputPtr++] & 0xFF;
}
if (currQuadBytes > 0) {
if (qlen >= quads.length) {
_quadBuffer = quads = growArrayBy(quads, quads.length);
}
quads[qlen++] = pad(currQuad, currQuadBytes);
}
String name = _symbols.findName(quads, qlen);
if (name == null) {
name = addName(quads, qlen, currQuadBytes);
}
return name;
}
/*
/**********************************************************
/* Internal methods, symbol (name) handling
/**********************************************************
*/
private final String findName(int q1, int lastQuadBytes) throws JsonParseException
{
q1 = pad(q1, lastQuadBytes);
// Usually we'll find it from the canonical symbol table already
String name = _symbols.findName(q1);
if (name != null) {
return name;
}
// If not, more work. We'll need add stuff to buffer
_quadBuffer[0] = q1;
return addName(_quadBuffer, 1, lastQuadBytes);
}
private final String findName(int q1, int q2, int lastQuadBytes) throws JsonParseException
{
q2 = pad(q2, lastQuadBytes);
// Usually we'll find it from the canonical symbol table already
String name = _symbols.findName(q1, q2);
if (name != null) {
return name;
}
// If not, more work. We'll need add stuff to buffer
_quadBuffer[0] = q1;
_quadBuffer[1] = q2;
return addName(_quadBuffer, 2, lastQuadBytes);
}
private final String findName(int q1, int q2, int q3, int lastQuadBytes) throws JsonParseException
{
q3 = pad(q3, lastQuadBytes);
String name = _symbols.findName(q1, q2, q3);
if (name != null) {
return name;
}
int[] quads = _quadBuffer;
quads[0] = q
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>1;
quads[1] = q2;
quads[2] = pad(q3, lastQuadBytes);
return addName(quads, 3, lastQuadBytes);
}
private final String findName(int[] quads, int qlen, int lastQuad, int lastQuadBytes) throws JsonParseException
{
if (qlen >= quads.length) {
_quadBuffer = quads = growArrayBy(quads, quads.length);
}
quads[qlen++] = pad(lastQuad, lastQuadBytes);
String name = _symbols.findName(quads, qlen);
if (name == null) {
return addName(quads, qlen, lastQuadBytes);
}
return name;
}
/**
* This is the main workhorse method used when we take a symbol
* table miss. It needs to demultiplex individual bytes, decode
* multi-byte chars (if any), and then construct Name instance
* and add it to the symbol table.
*/
private final String addName(int[] quads, int qlen, int lastQuadBytes) throws JsonParseException
{
/* Ok: must decode UTF-8 chars. No other validation is
* needed, since unescaping has been done earlier as necessary
* (as well as error reporting for unescaped control chars)
*/
// 4 bytes per quad, except last one maybe less
int byteLen = (qlen << 2) - 4 + lastQuadBytes;
/* And last one is not correctly aligned (leading zero bytes instead
* need to shift a bit, instead of trailing). Only need to shift it
* for UTF-8 decoding; need revert for storage (since key will not
* be aligned, to optimize lookup speed)
*/
int lastQuad;
if (lastQuadBytes < 4) {
lastQuad = quads[qlen-1];
// 8/16/24 bit left shift
quads[qlen-1] = (lastQuad << ((4 - lastQuadBytes) << 3));
} else {
lastQuad = 0;
}
// Need some working space, TextBuffer works well:
char[] cbuf = _textBuffer.emptyAndGetCurrentSegment();
int cix = 0;
for (int ix = 0
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> > 2) { // 4 bytes? (need surrogates on output)
ch2 = quads[ix >> 2];
byteIx = (ix & 3);
ch2 = (ch2 >> ((3 - byteIx) << 3));
++ix;
if ((ch2 & 0xC0) != 0x080) {
_reportInvalidOther(ch2 & 0xFF);
}
ch = (ch << 6) | (ch2 & 0x3F);
}
}
if (needed > 2) { // surrogate pair? once again, let's output one here, one later on
ch -= 0x10000; // to normalize it starting with 0x0
if (cix >= cbuf.length) {
cbuf = _textBuffer.expandCurrentSegment();
}
cbuf[cix++] = (char) (0xD800 + (ch >> 10));
ch = 0xDC00 | (ch & 0x03FF);
}
}
if (cix >= cbuf.length) {
cbuf = _textBuffer.expandCurrentSegment();
}
cbuf[cix++] = (char) ch;
}
// Ok. Now we have the character array, and can construct the String
String baseName = new String(cbuf, 0, cix);
// And finally, un-align if necessary
if (lastQuadBytes < 4) {
quads[qlen-1] = lastQuad;
}
return _symbols.addName(baseName, quads, qlen);
}
/*
/**********************************************************
/* Internal methods, String value parsing
/**********************************************************
*/
@Override
protected void _finishString() throws IOException
{
// First, single tight loop for ASCII content, not split across input buffer boundary:
int ptr = _inputPtr;
if (ptr >= _inputEnd) {
loadMoreGuaranteed();
ptr = _inputPtr;
}
int outPtr = 0;
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
final int[] codes = _icUTF8;
final int max = Math.min(_inputEnd, (ptr + outBuf.length));
final byte[] inputBuffer = _inputBuffer;
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
while (ptr < max) {
int c = (int) inputBuffer[ptr] & 0xFF;
if (codes[c] != 0) {
if (c == INT_QUOTE) {
_inputPtr = ptr+1;
_textBuffer.setCurrentLength(outPtr);
return;
}
break;
}
++ptr;
outBuf[outPtr++] = (char) c;
}
_inputPtr = ptr;
_finishString2(outBuf, outPtr);
}
/**
* @since 2.6
*/
protected String _finishAndReturnString() throws IOException
{
// First, single tight loop for ASCII content, not split across input buffer boundary:
int ptr = _inputPtr;
if (ptr >= _inputEnd) {
loadMoreGuaranteed();
ptr = _inputPtr;
}
int outPtr = 0;
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
final int[] codes = _icUTF8;
final int max = Math.min(_inputEnd, (ptr + outBuf.length));
final byte[] inputBuffer = _inputBuffer;
while (ptr < max) {
int c = (int) inputBuffer[ptr] & 0xFF;
if (codes[c] != 0) {
if (c == INT_QUOTE) {
_inputPtr = ptr+1;
return _textBuffer.setCurrentAndReturn(outPtr);
}
break;
}
++ptr;
outBuf[outPtr++] = (char) c;
}
_inputPtr = ptr;
_finishString2(outBuf, outPtr);
return _textBuffer.contentsAsString();
}
private final void _finishString2(char[] outBuf, int outPtr)
throws IOException
{
int c;
// Here we do want to do full decoding, hence:
final int[] codes = _icUTF8;
final byte[] inputBuffer = _inputBuffer;
main_loop:
while (true) {
// Then the tight ASCII non-funny-char loop:
ascii_loop:
while (true) {
int ptr = _inputPtr;
if (ptr >= _inputEnd) {
loadMoreGuaranteed();
ptr = _inputPtr;
}
if (outPtr >= outBuf
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
final int max = Math.min(_inputEnd, (ptr + (outBuf.length - outPtr)));
while (ptr < max) {
c = (int) inputBuffer[ptr++] & 0xFF;
if (codes[c] != 0) {
_inputPtr = ptr;
break ascii_loop;
}
outBuf[outPtr++] = (char) c;
}
_inputPtr = ptr;
}
// Ok: end marker, escape or multi-byte?
if (c == INT_QUOTE) {
break main_loop;
}
switch (codes[c]) {
case 1: // backslash
c = _decodeEscaped();
break;
case 2: // 2-byte UTF
c = _decodeUtf8_2(c);
break;
case 3: // 3-byte UTF
if ((_inputEnd - _inputPtr) >= 2) {
c = _decodeUtf8_3fast(c);
} else {
c = _decodeUtf8_3(c);
}
break;
case 4: // 4-byte UTF
c = _decodeUtf8_4(c);
// Let's add first part right away:
outBuf[outPtr++] = (char) (0xD800 | (c >> 10));
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
c = 0xDC00 | (c & 0x3FF);
// And let the other char output down below
break;
default:
if (c < INT_SPACE) {
// As per [JACKSON-208], call can now return:
_throwUnquotedSpace(c, "string value");
} else {
// Is this good enough error message?
_reportInvalidChar(c);
}
}
// Need more room?
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
// Ok, let's add char to output:
outBuf[outPtr++] = (char) c;
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
_textBuffer.setCurrentLength(outPtr);
}
/**
* Method called to skim through rest of unparsed String value,
* if it is not needed. This can be done bit faster if contents
* need not be stored for future access.
*/
protected void _skipString() throws IOException
{
_tokenIncomplete = false;
// Need to be fully UTF-8 aware here:
final int[] codes = _icUTF8;
final byte[] inputBuffer = _inputBuffer;
main_loop:
while (true) {
int c;
ascii_loop:
while (true) {
int ptr = _inputPtr;
int max = _inputEnd;
if (ptr >= max) {
loadMoreGuaranteed();
ptr = _inputPtr;
max = _inputEnd;
}
while (ptr < max) {
c = (int) inputBuffer[ptr++] & 0xFF;
if (codes[c] != 0) {
_inputPtr = ptr;
break ascii_loop;
}
}
_inputPtr = ptr;
}
// Ok: end marker, escape or multi-byte?
if (c == INT_QUOTE) {
break main_loop;
}
switch (codes[c]) {
case 1: // backslash
_decodeEscaped();
break;
case 2: // 2-byte UTF
_skipUtf8_2();
break;
case 3: // 3-byte UTF
_skipUtf8_3();
break;
case 4: // 4-byte UTF
_skipUtf8_4(c);
break;
default:
if (c < INT_SPACE) {
_throwUnquotedSpace(c, "string value");
} else {
// Is this good enough error message?
_reportInvalidChar(c);
}
}
}
}
/**
* Method for handling cases where first non-space character
* of an expected value token is not legal for standard JSON content.
*/
protected JsonToken _handleUnexpectedValue(int c)
throws IOException
{
// Most likely an error, unless we are to allow single-quote-strings
switch (c) {
case ']':
case '}':
// Error: neither is valid at this point; valid closers have
// been handled earlier
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> _reportUnexpectedChar(c, "expected a value");
case '\'':
if (isEnabled(Feature.ALLOW_SINGLE_QUOTES)) {
return _handleApos();
}
break;
case 'N':
_matchToken("NaN", 1);
if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
return resetAsNaN("NaN", Double.NaN);
}
_reportError("Non-standard token 'NaN': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
break;
case 'I':
_matchToken("Infinity", 1);
if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
return resetAsNaN("Infinity", Double.POSITIVE_INFINITY);
}
_reportError("Non-standard token 'Infinity': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
break;
case '+': // note: '-' is taken as number
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
_reportInvalidEOFInValue();
}
}
return _handleInvalidNumberStart(_inputBuffer[_inputPtr++] & 0xFF, false);
}
// [Issue#77] Try to decode most likely token
if (Character.isJavaIdentifierStart(c)) {
_reportInvalidToken(""+((char) c), "('true', 'false' or 'null')");
}
// but if it doesn't look like a token:
_reportUnexpectedChar(c, "expected a valid value (number, String, array, object, 'true', 'false' or 'null')");
return null;
}
protected JsonToken _handleApos()
throws IOException
{
int c = 0;
// Otherwise almost verbatim copy of _finishString()
int outPtr = 0;
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
// Here we do want to do full decoding, hence:
final int[] codes = _icUTF8;
final byte[] inputBuffer = _inputBuffer;
main_loop:
while (true) {
// Then the tight ascii non-funny-char loop:
ascii_loop:
while (true) {
if (_inputPtr >= _inputEnd) {
loadMoreGuaranteed();
}
if (outPtr >= out
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>Buf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
int max = _inputEnd;
{
int max2 = _inputPtr + (outBuf.length - outPtr);
if (max2 < max) {
max = max2;
}
}
while (_inputPtr < max) {
c = (int) inputBuffer[_inputPtr++] & 0xFF;
if (c == '\'' || codes[c] != 0) {
break ascii_loop;
}
outBuf[outPtr++] = (char) c;
}
}
// Ok: end marker, escape or multi-byte?
if (c == '\'') {
break main_loop;
}
switch (codes[c]) {
case 1: // backslash
c = _decodeEscaped();
break;
case 2: // 2-byte UTF
c = _decodeUtf8_2(c);
break;
case 3: // 3-byte UTF
if ((_inputEnd - _inputPtr) >= 2) {
c = _decodeUtf8_3fast(c);
} else {
c = _decodeUtf8_3(c);
}
break;
case 4: // 4-byte UTF
c = _decodeUtf8_4(c);
// Let's add first part right away:
outBuf[outPtr++] = (char) (0xD800 | (c >> 10));
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
c = 0xDC00 | (c & 0x3FF);
// And let the other char output down below
break;
default:
if (c < INT_SPACE) {
_throwUnquotedSpace(c, "string value");
}
// Is this good enough error message?
_reportInvalidChar(c);
}
// Need more room?
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
// Ok, let's add char to output:
outBuf[outPtr++] = (char) c;
}
_textBuffer.setCurrentLength(
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>outPtr);
return JsonToken.VALUE_STRING;
}
/**
* Method called if expected numeric value (due to leading sign) does not
* look like a number
*/
protected JsonToken _handleInvalidNumberStart(int ch, boolean neg)
throws IOException
{
while (ch == 'I') {
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
_reportInvalidEOFInValue();
}
}
ch = _inputBuffer[_inputPtr++];
String match;
if (ch == 'N') {
match = neg ? "-INF" :"+INF";
} else if (ch == 'n') {
match = neg ? "-Infinity" :"+Infinity";
} else {
break;
}
_matchToken(match, 3);
if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
return resetAsNaN(match, neg ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY);
}
_reportError("Non-standard token '"+match+"': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
}
reportUnexpectedNumberChar(ch, "expected digit (0-9) to follow minus sign, for valid numeric value");
return null;
}
protected final void _matchToken(String matchStr, int i) throws IOException
{
final int len = matchStr.length();
if ((_inputPtr + len) >= _inputEnd) {
_matchToken2(matchStr, i);
return;
}
do {
if (_inputBuffer[_inputPtr] != matchStr.charAt(i)) {
_reportInvalidToken(matchStr.substring(0, i));
}
++_inputPtr;
} while (++i < len);
int ch = _inputBuffer[_inputPtr] & 0xFF;
if (ch >= '0' && ch != ']' && ch != '}') { // expected/allowed chars
_checkMatchEnd(matchStr, i, ch);
}
}
private final void _matchToken2(String matchStr, int i) throws IOException
{
final int len = matchStr.length();
do {
if (((_inputPtr >= _inputEnd) && !loadMore())
|| (_inputBuffer[_inputPtr] != matchStr.charAt(i))) {
_reportInvalidToken
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>matchedPart);
/* Let's just try to find what appears to be the token, using
* regular Java identifier character rules. It's just a heuristic,
* nothing fancy here (nor fast).
*/
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
break;
}
int i = (int) _inputBuffer[_inputPtr++];
char c = (char) _decodeCharForError(i);
if (!Character.isJavaIdentifierPart(c)) {
break;
}
sb.append(c);
}
_reportError("Unrecognized token '"+sb.toString()+"': was expecting "+msg);
}
protected void _reportInvalidChar(int c)
throws JsonParseException
{
// Either invalid WS or illegal UTF-8 start char
if (c < INT_SPACE) {
_throwInvalidSpace(c);
}
_reportInvalidInitial(c);
}
protected void _reportInvalidInitial(int mask)
throws JsonParseException
{
_reportError("Invalid UTF-8 start byte 0x"+Integer.toHexString(mask));
}
protected void _reportInvalidOther(int mask)
throws JsonParseException
{
_reportError("Invalid UTF-8 middle byte 0x"+Integer.toHexString(mask));
}
protected void _reportInvalidOther(int mask, int ptr)
throws JsonParseException
{
_inputPtr = ptr;
_reportInvalidOther(mask);
}
public static int[] growArrayBy(int[] arr, int more)
{
if (arr == null) {
return new int[more];
}
return Arrays.copyOf(arr, arr.length + more);
}
/*
/**********************************************************
/* Internal methods, binary access
/**********************************************************
*/
/**
* Efficient handling for incremental parsing of base64-encoded
* textual content.
*/
@SuppressWarnings("resource")
protected final byte[] _decodeBase64(Base64Variant b64variant) throws IOException
{
ByteArrayBuilder builder = _getByteArrayBuilder();
//main_loop:
while (true) {
// first, we'll skip preceding white space, if any
int ch;
do {
if (_inputPtr >= _inputEnd) {
loadMoreGuaranteed();
}
ch = (int) _inputBuffer[_inputPtr
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> }
// let's just advance ptr to end
int origPtr = _inputPtr;
w.write(_inputBuffer, origPtr, count);
return count;
}
@Override public Object getInputSource() { return _reader; }
@Override
protected boolean loadMore() throws IOException
{
final int bufSize = _inputEnd;
_currInputProcessed += bufSize;
_currInputRowStart -= bufSize;
// 26-Nov-2015, tatu: Since name-offset requires it too, must offset
// this increase to avoid "moving" name-offset, resulting most likely
// in negative value, which is fine as combine value remains unchanged.
_nameStartOffset -= bufSize;
if (_reader != null) {
int count = _reader.read(_inputBuffer, 0, _inputBuffer.length);
if (count > 0) {
_inputPtr = 0;
_inputEnd = count;
return true;
}
// End of input
_closeInput();
// Should never return 0, so let's fail
if (count == 0) {
throw new IOException("Reader returned 0 characters when trying to read "+_inputEnd);
}
}
return false;
}
protected char getNextChar(String eofMsg) throws IOException {
if (_inputPtr >= _inputEnd) {
if (!loadMore()) { _reportInvalidEOF(eofMsg); }
}
return _inputBuffer[_inputPtr++];
}
@Override
protected void _closeInput() throws IOException {
/* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
* on the underlying Reader, unless we "own" it, or auto-closing
* feature is enabled.
* One downside is that when using our optimized
* Reader (granted, we only do that for UTF-32...) this
* means that buffer recycling won't work correctly.
*/
if (_reader != null) {
if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_SOURCE)) {
_reader.close();
}
_reader = null;
}
}
/**
* Method called to release internal buffers owned by the base
* reader. This may be
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> called along with {@link #_closeInput} (for
* example, when explicitly closing this reader instance), or
* separately (if need be).
*/
@Override
protected void _releaseBuffers() throws IOException {
super._releaseBuffers();
// merge new symbols, if any
_symbols.release();
// and release buffers, if they are recyclable ones
if (_bufferRecyclable) {
char[] buf = _inputBuffer;
if (buf != null) {
_inputBuffer = null;
_ioContext.releaseTokenBuffer(buf);
}
}
}
/*
/**********************************************************
/* Public API, data access
/**********************************************************
*/
/**
* Method for accessing textual representation of the current event;
* if no current event (before first call to {@link #nextToken}, or
* after encountering end-of-input), returns null.
* Method can be called for any event.
*/
@Override
public final String getText() throws IOException
{
JsonToken t = _currToken;
if (t == JsonToken.VALUE_STRING) {
if (_tokenIncomplete) {
_tokenIncomplete = false;
_finishString(); // only strings can be incomplete
}
return _textBuffer.contentsAsString();
}
return _getText2(t);
}
// // // Let's override default impls for improved performance
// @since 2.1
@Override
public final String getValueAsString() throws IOException
{
if (_currToken == JsonToken.VALUE_STRING) {
if (_tokenIncomplete) {
_tokenIncomplete = false;
_finishString(); // only strings can be incomplete
}
return _textBuffer.contentsAsString();
}
if (_currToken == JsonToken.FIELD_NAME) {
return getCurrentName();
}
return super.getValueAsString(null);
}
// @since 2.1
@Override
public final String getValueAsString(String defValue) throws IOException {
if (_currToken == JsonToken.VALUE_STRING) {
if (_tokenIncomplete) {
_tokenIncomplete = false;
_finishString(); // only strings can be incomplete
}
return _textBuffer.contentsAsString();
}
if (_currToken == JsonToken.FIELD_NAME) {
return getCurrentName();
}
return super.getValueAsString(defValue);
}
protected final String _
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>getText2(JsonToken t) {
if (t == null) {
return null;
}
switch (t.id()) {
case ID_FIELD_NAME:
return _parsingContext.getCurrentName();
case ID_STRING:
// fall through
case ID_NUMBER_INT:
case ID_NUMBER_FLOAT:
return _textBuffer.contentsAsString();
default:
return t.asString();
}
}
@Override
public final char[] getTextCharacters() throws IOException
{
if (_currToken != null) { // null only before/after document
switch (_currToken.id()) {
case ID_FIELD_NAME:
if (!_nameCopied) {
String name = _parsingContext.getCurrentName();
int nameLen = name.length();
if (_nameCopyBuffer == null) {
_nameCopyBuffer = _ioContext.allocNameCopyBuffer(nameLen);
} else if (_nameCopyBuffer.length < nameLen) {
_nameCopyBuffer = new char[nameLen];
}
name.getChars(0, nameLen, _nameCopyBuffer, 0);
_nameCopied = true;
}
return _nameCopyBuffer;
case ID_STRING:
if (_tokenIncomplete) {
_tokenIncomplete = false;
_finishString(); // only strings can be incomplete
}
// fall through
case ID_NUMBER_INT:
case ID_NUMBER_FLOAT:
return _textBuffer.getTextBuffer();
default:
return _currToken.asCharArray();
}
}
return null;
}
@Override
public final int getTextLength() throws IOException
{
if (_currToken != null) { // null only before/after document
switch (_currToken.id()) {
case ID_FIELD_NAME:
return _parsingContext.getCurrentName().length();
case ID_STRING:
if (_tokenIncomplete) {
_tokenIncomplete = false;
_finishString(); // only strings can be incomplete
}
// fall through
case ID_NUMBER_INT:
case ID_NUMBER_FLOAT:
return _textBuffer.size();
default:
return _currToken.asCharArray().length;
}
}
return 0;
}
@Override
public final int getTextOffset() throws IOException
{
// Most have offset of 0, only some may have other values:
if (_curr
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>Token != null) {
switch (_currToken.id()) {
case ID_FIELD_NAME:
return 0;
case ID_STRING:
if (_tokenIncomplete) {
_tokenIncomplete = false;
_finishString(); // only strings can be incomplete
}
// fall through
case ID_NUMBER_INT:
case ID_NUMBER_FLOAT:
return _textBuffer.getTextOffset();
default:
}
}
return 0;
}
@Override
public byte[] getBinaryValue(Base64Variant b64variant) throws IOException
{
if (_currToken != JsonToken.VALUE_STRING &&
(_currToken != JsonToken.VALUE_EMBEDDED_OBJECT || _binaryValue == null)) {
_reportError("Current token ("+_currToken+") not VALUE_STRING or VALUE_EMBEDDED_OBJECT, can not access as binary");
}
/* To ensure that we won't see inconsistent data, better clear up
* state...
*/
if (_tokenIncomplete) {
try {
_binaryValue = _decodeBase64(b64variant);
} catch (IllegalArgumentException iae) {
throw _constructError("Failed to decode VALUE_STRING as base64 ("+b64variant+"): "+iae.getMessage());
}
/* let's clear incomplete only now; allows for accessing other
* textual content in error cases
*/
_tokenIncomplete = false;
} else { // may actually require conversion...
if (_binaryValue == null) {
@SuppressWarnings("resource")
ByteArrayBuilder builder = _getByteArrayBuilder();
_decodeBase64(getText(), builder, b64variant);
_binaryValue = builder.toByteArray();
}
}
return _binaryValue;
}
@Override
public int readBinaryValue(Base64Variant b64variant, OutputStream out) throws IOException
{
// if we have already read the token, just use whatever we may have
if (!_tokenIncomplete || _currToken != JsonToken.VALUE_STRING) {
byte[] b = getBinaryValue(b64variant);
out.write(b);
return b.length;
}
// otherwise do "real" incremental parsing...
byte[] buf = _ioContext.allocBase64Buffer();
try {
return _readBinary(b64variant, out, buf);
} finally {
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> _ioContext.releaseBase64Buffer(buf);
}
}
protected int _readBinary(Base64Variant b64variant, OutputStream out, byte[] buffer) throws IOException
{
int outputPtr = 0;
final int outputEnd = buffer.length - 3;
int outputCount = 0;
while (true) {
// first, we'll skip preceding white space, if any
char ch;
do {
if (_inputPtr >= _inputEnd) {
loadMoreGuaranteed();
}
ch = _inputBuffer[_inputPtr++];
} while (ch <= INT_SPACE);
int bits = b64variant.decodeBase64Char(ch);
if (bits < 0) { // reached the end, fair and square?
if (ch == '"') {
break;
}
bits = _decodeBase64Escape(b64variant, ch, 0);
if (bits < 0) { // white space to skip
continue;
}
}
// enough room? If not, flush
if (outputPtr > outputEnd) {
outputCount += outputPtr;
out.write(buffer, 0, outputPtr);
outputPtr = 0;
}
int decodedData = bits;
// then second base64 char; can't get padding yet, nor ws
if (_inputPtr >= _inputEnd) {
loadMoreGuaranteed();
}
ch = _inputBuffer[_inputPtr++];
bits = b64variant.decodeBase64Char(ch);
if (bits < 0) {
bits = _decodeBase64Escape(b64variant, ch, 1);
}
decodedData = (decodedData << 6) | bits;
// third base64 char; can be padding, but not ws
if (_inputPtr >= _inputEnd) {
loadMoreGuaranteed();
}
ch = _inputBuffer[_inputPtr++];
bits = b64variant.decodeBase64Char(ch);
// First branch: can get padding (-> 1 byte)
if (bits < 0) {
if (bits != Base64Variant.BASE64_VALUE_PADDING) {
// as per [JACKSON-631], could also just be 'missing' padding
if (ch == '"' && !b
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> (i == INT_RCURLY) {
_updateLocation();
if (!_parsingContext.inObject()) {
_reportMismatchedEndMarker(i, ']');
}
_parsingContext = _parsingContext.clearAndGetParent();
_currToken = JsonToken.END_OBJECT;
return false;
}
if (_parsingContext.expectComma()) {
i = _skipComma(i);
}
if (!_parsingContext.inObject()) {
_updateLocation();
_nextTokenNotInObject(i);
return false;
}
_updateNameLocation();
if (i == INT_QUOTE) {
// when doing literal match, must consider escaping:
char[] nameChars = sstr.asQuotedChars();
final int len = nameChars.length;
// Require 4 more bytes for faster skipping of colon that follows name
if ((_inputPtr + len + 4) < _inputEnd) { // maybe...
// first check length match by
final int end = _inputPtr+len;
if (_inputBuffer[end] == '"') {
int offset = 0;
int ptr = _inputPtr;
while (true) {
if (ptr == end) { // yes, match!
_parsingContext.setCurrentName(sstr.getValue());
_isNextTokenNameYes(_skipColonFast(ptr+1));
return true;
}
if (nameChars[offset] != _inputBuffer[ptr]) {
break;
}
++offset;
++ptr;
}
}
}
}
return _isNextTokenNameMaybe(i, sstr.getValue());
}
@Override
public String nextFieldName() throws IOException
{
// // // Note: this is almost a verbatim copy of nextToken() (minus comments)
_numTypesValid = NR_UNKNOWN;
if (_currToken == JsonToken.FIELD_NAME) {
_nextAfterName();
return null;
}
if (_tokenIncomplete) {
_skipString();
}
int i = _skipWSOrEnd();
if (i < 0) {
close();
_currToken = null;
return null;
}
_binaryValue = null;
if (i == INT_RBRACKET) {
_updateLocation();
if (!_parsingContext.inArray()) {
_reportMismatchedEndMarker(i, '}');
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> null;
_currToken = t;
if (t == JsonToken.VALUE_STRING) {
if (_tokenIncomplete) {
_tokenIncomplete = false;
_finishString();
}
return _textBuffer.contentsAsString();
}
if (t == JsonToken.START_ARRAY) {
_parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
} else if (t == JsonToken.START_OBJECT) {
_parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
}
return null;
}
// !!! TODO: optimize this case as well
return (nextToken() == JsonToken.VALUE_STRING) ? getText() : null;
}
// note: identical to one in Utf8StreamParser
@Override
public final int nextIntValue(int defaultValue) throws IOException
{
if (_currToken == JsonToken.FIELD_NAME) {
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
_currToken = t;
if (t == JsonToken.VALUE_NUMBER_INT) {
return getIntValue();
}
if (t == JsonToken.START_ARRAY) {
_parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
} else if (t == JsonToken.START_OBJECT) {
_parsingContext = _parsingContext.createChildObjectContext(_tokenInputRow, _tokenInputCol);
}
return defaultValue;
}
// !!! TODO: optimize this case as well
return (nextToken() == JsonToken.VALUE_NUMBER_INT) ? getIntValue() : defaultValue;
}
// note: identical to one in Utf8StreamParser
@Override
public final long nextLongValue(long defaultValue) throws IOException
{
if (_currToken == JsonToken.FIELD_NAME) { // mostly copied from '_nextAfterName'
_nameCopied = false;
JsonToken t = _nextToken;
_nextToken = null;
_currToken = t;
if (t == JsonToken.VALUE_NUMBER_INT) {
return getLongValue();
}
if (t == JsonToken.START_ARRAY) {
_parsingContext = _parsingContext.createChildArrayContext(_tokenInputRow, _tokenInputCol);
} else if (
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> protected final JsonToken _parsePosNumber(int ch) throws IOException
{
/* Although we will always be complete with respect to textual
* representation (that is, all characters will be parsed),
* actual conversion to a number is deferred. Thus, need to
* note that no representations are valid yet
*/
int ptr = _inputPtr;
int startPtr = ptr-1; // to include digit already read
final int inputLen = _inputEnd;
// One special case, leading zero(es):
if (ch == INT_0) {
return _parseNumber2(false, startPtr);
}
/* First, let's see if the whole number is contained within
* the input buffer unsplit. This should be the common case;
* and to simplify processing, we will just reparse contents
* in the alternative case (number split on buffer boundary)
*/
int intLen = 1; // already got one
// First let's get the obligatory integer part:
int_loop:
while (true) {
if (ptr >= inputLen) {
_inputPtr = startPtr;
return _parseNumber2(false, startPtr);
}
ch = (int) _inputBuffer[ptr++];
if (ch < INT_0 || ch > INT_9) {
break int_loop;
}
++intLen;
}
if (ch == INT_PERIOD || ch == INT_e || ch == INT_E) {
_inputPtr = ptr;
return _parseFloat(ch, startPtr, ptr, false, intLen);
}
// Got it all: let's add to text buffer for parsing, access
--ptr; // need to push back following separator
_inputPtr = ptr;
// As per #105, need separating space between root values; check here
if (_parsingContext.inRoot()) {
_verifyRootSpace(ch);
}
int len = ptr-startPtr;
_textBuffer.resetWithShared(_inputBuffer, startPtr, len);
return resetInt(false, intLen);
}
private final JsonToken _parseFloat(int ch, int startPtr, int ptr, boolean neg, int intLen)
throws IOException
{
final int inputLen = _inputEnd;
int fractLen = 0;
// And then see if we get other parts
if (ch ==
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> '.') { // yes, fraction
fract_loop:
while (true) {
if (ptr >= inputLen) {
return _parseNumber2(neg, startPtr);
}
ch = (int) _inputBuffer[ptr++];
if (ch < INT_0 || ch > INT_9) {
break fract_loop;
}
++fractLen;
}
// must be followed by sequence of ints, one minimum
if (fractLen == 0) {
reportUnexpectedNumberChar(ch, "Decimal point not followed by a digit");
}
}
int expLen = 0;
if (ch == 'e' || ch == 'E') { // and/or exponent
if (ptr >= inputLen) {
_inputPtr = startPtr;
return _parseNumber2(neg, startPtr);
}
// Sign indicator?
ch = (int) _inputBuffer[ptr++];
if (ch == INT_MINUS || ch == INT_PLUS) { // yup, skip for now
if (ptr >= inputLen) {
_inputPtr = startPtr;
return _parseNumber2(neg, startPtr);
}
ch = (int) _inputBuffer[ptr++];
}
while (ch <= INT_9 && ch >= INT_0) {
++expLen;
if (ptr >= inputLen) {
_inputPtr = startPtr;
return _parseNumber2(neg, startPtr);
}
ch = (int) _inputBuffer[ptr++];
}
// must be followed by sequence of ints, one minimum
if (expLen == 0) {
reportUnexpectedNumberChar(ch, "Exponent indicator not followed by a digit");
}
}
--ptr; // need to push back following separator
_inputPtr = ptr;
// As per #105, need separating space between root values; check here
if (_parsingContext.inRoot()) {
_verifyRootSpace(ch);
}
int len = ptr-startPtr;
_textBuffer.resetWithShared(_inputBuffer, startPtr, len);
// And there we have it!
return resetFloat(neg, intLen, fractLen, expLen);
}
protected final JsonToken _parseNegNumber() throws IOException
{
int ptr = _inputPtr;
int startPtr = ptr-1; // to
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> include sign/digit already read
final int inputLen = _inputEnd;
if (ptr >= inputLen) {
return _parseNumber2(true, startPtr);
}
int ch = _inputBuffer[ptr++];
// First check: must have a digit to follow minus sign
if (ch > INT_9 || ch < INT_0) {
_inputPtr = ptr;
return _handleInvalidNumberStart(ch, true);
}
// One special case, leading zero(es):
if (ch == INT_0) {
return _parseNumber2(true, startPtr);
}
int intLen = 1; // already got one
// First let's get the obligatory integer part:
int_loop:
while (true) {
if (ptr >= inputLen) {
return _parseNumber2(true, startPtr);
}
ch = (int) _inputBuffer[ptr++];
if (ch < INT_0 || ch > INT_9) {
break int_loop;
}
++intLen;
}
if (ch == INT_PERIOD || ch == INT_e || ch == INT_E) {
_inputPtr = ptr;
return _parseFloat(ch, startPtr, ptr, true, intLen);
}
--ptr;
_inputPtr = ptr;
if (_parsingContext.inRoot()) {
_verifyRootSpace(ch);
}
int len = ptr-startPtr;
_textBuffer.resetWithShared(_inputBuffer, startPtr, len);
return resetInt(true, intLen);
}
/**
* Method called to parse a number, when the primary parse
* method has failed to parse it, due to it being split on
* buffer boundary. As a result code is very similar, except
* that it has to explicitly copy contents to the text buffer
* instead of just sharing the main input buffer.
*/
private final JsonToken _parseNumber2(boolean neg, int startPtr) throws IOException
{
_inputPtr = neg ? (startPtr+1) : startPtr;
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
int outPtr = 0;
// Need to prepend sign?
if (neg) {
outBuf[outPtr++] = '-';
}
// This is the place to do leading-zero check(s) too
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>:
int intLen = 0;
char c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++] : getNextChar("No digit following minus sign");
if (c == '0') {
c = _verifyNoLeadingZeroes();
}
boolean eof = false;
// Ok, first the obligatory integer part:
int_loop:
while (c >= '0' && c <= '9') {
++intLen;
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
outBuf[outPtr++] = c;
}
// must be followed by sequence of ints, one minimum
if (fractLen == 0) {
reportUnexpectedNumberChar(c, "Decimal point not followed by a digit");
}
}
int expLen = 0;
if (c == 'e' || c == 'E') { // exponent?
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
outBuf[outPtr++] = c;
// Not optional, can require that we get one more char
c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++]
: getNextChar("expected a digit for number exponent");
// Sign indicator?
if (c == '-' || c == '+') {
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
outBuf[outPtr++] = c;
// Likewise, non optional:
c = (_inputPtr < _inputEnd) ? _inputBuffer[_inputPtr++]
: getNextChar("expected a digit for number exponent");
}
exp_loop:
while (c <= INT_9 && c >= INT_0) {
++expLen;
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break exp_loop
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>;
}
c = _inputBuffer[_inputPtr++];
}
// must be followed by sequence of ints, one minimum
if (expLen == 0) {
reportUnexpectedNumberChar(c, "Exponent indicator not followed by a digit");
}
}
// Ok; unless we hit end-of-input, need to push last char read back
if (!eof) {
--_inputPtr;
if (_parsingContext.inRoot()) {
_verifyRootSpace(c);
}
}
_textBuffer.setCurrentLength(outPtr);
// And there we have it!
return reset(neg, intLen, fractLen, expLen);
}
/**
* Method called when we have seen one zero, and want to ensure
* it is not followed by another
*/
private final char _verifyNoLeadingZeroes() throws IOException
{
// Fast case first:
if (_inputPtr < _inputEnd) {
char ch = _inputBuffer[_inputPtr];
// if not followed by a number (probably '.'); return zero as is, to be included
if (ch < '0' || ch > '9') {
return '0';
}
}
// and offline the less common case
return _verifyNLZ2();
}
private char _verifyNLZ2() throws IOException
{
if (_inputPtr >= _inputEnd && !loadMore()) {
return '0';
}
char ch = _inputBuffer[_inputPtr];
if (ch < '0' || ch > '9') {
return '0';
}
if (!isEnabled(Feature.ALLOW_NUMERIC_LEADING_ZEROS)) {
reportInvalidNumber("Leading zeroes not allowed");
}
// if so, just need to skip either all zeroes (if followed by number); or all but one (if non-number)
++_inputPtr; // Leading zero to be skipped
if (ch == INT_0) {
while (_inputPtr < _inputEnd || loadMore()) {
ch = _inputBuffer[_inputPtr];
if (ch < '0' || ch > '9') { // followed by non-number; retain one zero
return '0';
}
++_inputPtr; // skip previous zero
if (ch != '0') { // followed by other number; return
break;
}
}
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
*/
protected final String _parseName() throws IOException
{
// First: let's try to see if we have a simple name: one that does
// not cross input buffer boundary, and does not contain escape sequences.
int ptr = _inputPtr;
int hash = _hashSeed;
final int[] codes = _icLatin1;
while (ptr < _inputEnd) {
int ch = _inputBuffer[ptr];
if (ch < codes.length && codes[ch] != 0) {
if (ch == '"') {
int start = _inputPtr;
_inputPtr = ptr+1; // to skip the quote
return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash);
}
break;
}
hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + ch;
++ptr;
}
int start = _inputPtr;
_inputPtr = ptr;
return _parseName2(start, hash, INT_QUOTE);
}
private String _parseName2(int startPtr, int hash, int endChar) throws IOException
{
_textBuffer.resetWithShared(_inputBuffer, startPtr, (_inputPtr - startPtr));
/* Output pointers; calls will also ensure that the buffer is
* not shared and has room for at least one more char.
*/
char[] outBuf = _textBuffer.getCurrentSegment();
int outPtr = _textBuffer.getCurrentSegmentSize();
while (true) {
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
_reportInvalidEOF(": was expecting closing '"+((char) endChar)+"' for name");
}
}
char c = _inputBuffer[_inputPtr++];
int i = (int) c;
if (i <= INT_BACKSLASH) {
if (i == INT_BACKSLASH) {
/* Although chars outside of BMP are to be escaped as
* an UTF-16 surrogate pair, does that affect decoding?
* For now let's assume it does not.
*/
c = _decodeEscaped();
} else if (i <= endChar) {
if (i == endChar) {
break;
}
if (i < INT_SPACE) {
_throwUnquotedSpace(i, "name");
}
}
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + c;
// Ok, let's add char to output:
outBuf[outPtr++] = c;
// Need more room?
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
}
_textBuffer.setCurrentLength(outPtr);
{
TextBuffer tb = _textBuffer;
char[] buf = tb.getTextBuffer();
int start = tb.getTextOffset();
int len = tb.size();
return _symbols.findSymbol(buf, start, len, hash);
}
}
/**
* Method called when we see non-white space character other
* than double quote, when expecting a field name.
* In standard mode will just throw an expection; but
* in non-standard modes may be able to parse name.
*/
protected String _handleOddName(int i) throws IOException
{
// [JACKSON-173]: allow single quotes
if (i == '\'' && isEnabled(Feature.ALLOW_SINGLE_QUOTES)) {
return _parseAposName();
}
// [JACKSON-69]: allow unquoted names if feature enabled:
if (!isEnabled(Feature.ALLOW_UNQUOTED_FIELD_NAMES)) {
_reportUnexpectedChar(i, "was expecting double-quote to start field name");
}
final int[] codes = CharTypes.getInputCodeLatin1JsNames();
final int maxCode = codes.length;
// Also: first char must be a valid name char, but NOT be number
boolean firstOk;
if (i < maxCode) { // identifier, or a number ([Issue#102])
firstOk = (codes[i] == 0);
} else {
firstOk = Character.isJavaIdentifierPart((char) i);
}
if (!firstOk) {
_reportUnexpectedChar(i, "was expecting either valid name character (for unquoted name) or double-quote (for quoted) to start field name");
}
int ptr = _inputPtr;
int hash = _hashSeed;
final int inputLen = _inputEnd;
if (ptr < inputLen) {
do {
int ch = _inputBuffer[ptr];
if (ch < maxCode
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>) {
if (codes[ch] != 0) {
int start = _inputPtr-1; // -1 to bring back first char
_inputPtr = ptr;
return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash);
}
} else if (!Character.isJavaIdentifierPart((char) ch)) {
int start = _inputPtr-1; // -1 to bring back first char
_inputPtr = ptr;
return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash);
}
hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + ch;
++ptr;
} while (ptr < inputLen);
}
int start = _inputPtr-1;
_inputPtr = ptr;
return _handleOddName2(start, hash, codes);
}
protected String _parseAposName() throws IOException
{
// Note: mostly copy of_parseFieldName
int ptr = _inputPtr;
int hash = _hashSeed;
final int inputLen = _inputEnd;
if (ptr < inputLen) {
final int[] codes = _icLatin1;
final int maxCode = codes.length;
do {
int ch = _inputBuffer[ptr];
if (ch == '\'') {
int start = _inputPtr;
_inputPtr = ptr+1; // to skip the quote
return _symbols.findSymbol(_inputBuffer, start, ptr - start, hash);
}
if (ch < maxCode && codes[ch] != 0) {
break;
}
hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + ch;
++ptr;
} while (ptr < inputLen);
}
int start = _inputPtr;
_inputPtr = ptr;
return _parseName2(start, hash, '\'');
}
/**
* Method for handling cases where first non-space character
* of an expected value token is not legal for standard JSON content.
*/
protected JsonToken _handleOddValue(int i) throws IOException
{
// Most likely an error, unless we are to allow single-quote-strings
switch (i) {
case '\'':
/* [JACKSON-173]: allow single quotes. Unlike with regular
* Strings, we'll eagerly parse contents
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>; this so that there's
* no need to store information on quote char used.
*
* Also, no separation to fast/slow parsing; we'll just do
* one regular (~= slowish) parsing, to keep code simple
*/
if (isEnabled(Feature.ALLOW_SINGLE_QUOTES)) {
return _handleApos();
}
break;
case 'N':
_matchToken("NaN", 1);
if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
return resetAsNaN("NaN", Double.NaN);
}
_reportError("Non-standard token 'NaN': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
break;
case 'I':
_matchToken("Infinity", 1);
if (isEnabled(Feature.ALLOW_NON_NUMERIC_NUMBERS)) {
return resetAsNaN("Infinity", Double.POSITIVE_INFINITY);
}
_reportError("Non-standard token 'Infinity': enable JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS to allow");
break;
case '+': // note: '-' is taken as number
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
_reportInvalidEOFInValue();
}
}
return _handleInvalidNumberStart(_inputBuffer[_inputPtr++], false);
}
// [Issue#77] Try to decode most likely token
if (Character.isJavaIdentifierStart(i)) {
_reportInvalidToken(""+((char) i), "('true', 'false' or 'null')");
}
// but if it doesn't look like a token:
_reportUnexpectedChar(i, "expected a valid value (number, String, array, object, 'true', 'false' or 'null')");
return null;
}
protected JsonToken _handleApos() throws IOException
{
char[] outBuf = _textBuffer.emptyAndGetCurrentSegment();
int outPtr = _textBuffer.getCurrentSegmentSize();
while (true) {
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
_reportInvalidEOF(": was expecting closing quote for a string value");
}
}
char c = _inputBuffer[_inputPtr++];
int i = (int) c;
if (i <= '\\') {
if (i == '\\') {
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> /* Although chars outside of BMP are to be escaped as
* an UTF-16 surrogate pair, does that affect decoding?
* For now let's assume it does not.
*/
c = _decodeEscaped();
} else if (i <= '\'') {
if (i == '\'') {
break;
}
if (i < INT_SPACE) {
_throwUnquotedSpace(i, "string value");
}
}
}
// Need more room?
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
// Ok, let's add char to output:
outBuf[outPtr++] = c;
}
_textBuffer.setCurrentLength(outPtr);
return JsonToken.VALUE_STRING;
}
private String _handleOddName2(int startPtr, int hash, int[] codes) throws IOException
{
_textBuffer.resetWithShared(_inputBuffer, startPtr, (_inputPtr - startPtr));
char[] outBuf = _textBuffer.getCurrentSegment();
int outPtr = _textBuffer.getCurrentSegmentSize();
final int maxCode = codes.length;
while (true) {
if (_inputPtr >= _inputEnd) {
if (!loadMore()) { // acceptable for now (will error out later)
break;
}
}
char c = _inputBuffer[_inputPtr];
int i = (int) c;
if (i <= maxCode) {
if (codes[i] != 0) {
break;
}
} else if (!Character.isJavaIdentifierPart(c)) {
break;
}
++_inputPtr;
hash = (hash * CharsToNameCanonicalizer.HASH_MULT) + i;
// Ok, let's add char to output:
outBuf[outPtr++] = c;
// Need more room?
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
}
_textBuffer.setCurrentLength(outPtr);
{
TextBuffer tb = _textBuffer;
char[] buf = tb.getTextBuffer();
int start = tb.getTextOffset();
int len = tb.size();
return _symbols.findSymbol(buf, start, len
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>, hash);
}
}
@Override
protected final void _finishString() throws IOException
{
/* First: let's try to see if we have simple String value: one
* that does not cross input buffer boundary, and does not
* contain escape sequences.
*/
int ptr = _inputPtr;
final int inputLen = _inputEnd;
if (ptr < inputLen) {
final int[] codes = _icLatin1;
final int maxCode = codes.length;
do {
int ch = _inputBuffer[ptr];
if (ch < maxCode && codes[ch] != 0) {
if (ch == '"') {
_textBuffer.resetWithShared(_inputBuffer, _inputPtr, (ptr-_inputPtr));
_inputPtr = ptr+1;
// Yes, we got it all
return;
}
break;
}
++ptr;
} while (ptr < inputLen);
}
/* Either ran out of input, or bumped into an escape
* sequence...
*/
_textBuffer.resetWithCopy(_inputBuffer, _inputPtr, (ptr-_inputPtr));
_inputPtr = ptr;
_finishString2();
}
protected void _finishString2() throws IOException
{
char[] outBuf = _textBuffer.getCurrentSegment();
int outPtr = _textBuffer.getCurrentSegmentSize();
final int[] codes = _icLatin1;
final int maxCode = codes.length;
while (true) {
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
_reportInvalidEOF(": was expecting closing quote for a string value");
}
}
char c = _inputBuffer[_inputPtr++];
int i = (int) c;
if (i < maxCode && codes[i] != 0) {
if (i == INT_QUOTE) {
break;
} else if (i == INT_BACKSLASH) {
/* Although chars outside of BMP are to be escaped as
* an UTF-16 surrogate pair, does that affect decoding?
* For now let's assume it does not.
*/
c = _decodeEscaped();
} else if (i < INT_SPACE) {
_throwUnquotedSpace(i, "string value");
} // anything else?
}
// Need more room?
if
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
// Ok, let's add char to output:
outBuf[outPtr++] = c;
}
_textBuffer.setCurrentLength(outPtr);
}
/**
* Method called to skim through rest of unparsed String value,
* if it is not needed. This can be done bit faster if contents
* need not be stored for future access.
*/
protected final void _skipString() throws IOException
{
_tokenIncomplete = false;
int inPtr = _inputPtr;
int inLen = _inputEnd;
char[] inBuf = _inputBuffer;
while (true) {
if (inPtr >= inLen) {
_inputPtr = inPtr;
if (!loadMore()) {
_reportInvalidEOF(": was expecting closing quote for a string value");
}
inPtr = _inputPtr;
inLen = _inputEnd;
}
char c = inBuf[inPtr++];
int i = (int) c;
if (i <= INT_BACKSLASH) {
if (i == INT_BACKSLASH) {
// Although chars outside of BMP are to be escaped as an UTF-16 surrogate pair,
// does that affect decoding? For now let's assume it does not.
_inputPtr = inPtr;
/*c = */ _decodeEscaped();
inPtr = _inputPtr;
inLen = _inputEnd;
} else if (i <= INT_QUOTE) {
if (i == INT_QUOTE) {
_inputPtr = inPtr;
break;
}
if (i < INT_SPACE) {
_inputPtr = inPtr;
_throwUnquotedSpace(i, "string value");
}
}
}
}
}
/*
/**********************************************************
/* Internal methods, other parsing
/**********************************************************
*/
/**
* We actually need to check the character value here
* (to see if we have \n following \r).
*/
protected final void _skipCR() throws IOException {
if (_inputPtr < _inputEnd || loadMore()) {
if (_inputBuffer[_inputPtr] == '\n') {
++_inputPtr;
}
}
++_currInputRow;
_currInput
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> }
}
}
// buffer boundary, or problem, offline
_matchToken("true", 1);
}
private final void _matchFalse() throws IOException {
int ptr = _inputPtr;
if ((ptr + 4) < _inputEnd) {
final char[] b = _inputBuffer;
if (b[ptr] == 'a' && b[++ptr] == 'l' && b[++ptr] == 's' && b[++ptr] == 'e') {
char c = b[++ptr];
if (c < '0' || c == ']' || c == '}') { // expected/allowed chars
_inputPtr = ptr;
return;
}
}
}
// buffer boundary, or problem, offline
_matchToken("false", 1);
}
private final void _matchNull() throws IOException {
int ptr = _inputPtr;
if ((ptr + 3) < _inputEnd) {
final char[] b = _inputBuffer;
if (b[ptr] == 'u' && b[++ptr] == 'l' && b[++ptr] == 'l') {
char c = b[++ptr];
if (c < '0' || c == ']' || c == '}') { // expected/allowed chars
_inputPtr = ptr;
return;
}
}
}
// buffer boundary, or problem, offline
_matchToken("null", 1);
}
/**
* Helper method for checking whether input matches expected token
*/
protected final void _matchToken(String matchStr, int i) throws IOException
{
final int len = matchStr.length();
do {
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
_reportInvalidToken(matchStr.substring(0, i));
}
}
if (_inputBuffer[_inputPtr] != matchStr.charAt(i)) {
_reportInvalidToken(matchStr.substring(0, i));
}
++_inputPtr;
} while (++i < len);
// but let's also ensure we either get EOF, or non-alphanum char...
if (_inputPtr >= _inputEnd) {
if (!loadMore()) {
return;
}
}
char c = _inputBuffer[_inputPtr];
if (c < '0' || c == ']' || c == '
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> parser, it will still be managed (i.e. closed if
* end-of-stream is reacher, or parser close method called)
* if (and only if) {@link com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE}
* is enabled.
*<p>
*
* Note: no encoding argument is taken since it can always be
* auto-detected as suggested by JSON RFC. Json specification
* supports only UTF-8, UTF-16 and UTF-32 as valid encodings,
* so auto-detection implemented only for this charsets.
* For other charsets use {@link #createParser(java.io.Reader)}.
*
* @param in InputStream to use for reading JSON content to parse
*
* @since 2.1
*/
public JsonParser createParser(InputStream in) throws IOException, JsonParseException {
IOContext ctxt = _createContext(in, false);
return _createParser(_decorate(in, ctxt), ctxt);
}
/**
* Method for constructing parser for parsing
* the contents accessed via specified Reader.
<p>
* The read stream will <b>not be owned</b> by
* the parser, it will still be managed (i.e. closed if
* end-of-stream is reacher, or parser close method called)
* if (and only if) {@link com.fasterxml.jackson.core.JsonParser.Feature#AUTO_CLOSE_SOURCE}
* is enabled.
*
* @param r Reader to use for reading JSON content to parse
*
* @since 2.1
*/
public JsonParser createParser(Reader r) throws IOException, JsonParseException {
// false -> we do NOT own Reader (did not create it)
IOContext ctxt = _createContext(r, false);
return _createParser(_decorate(r, ctxt), ctxt);
}
/**
* Method for constructing parser for parsing
* the contents of given byte array.
*
* @since 2.1
*/
public JsonParser createParser(byte[] data) throws IOException, JsonParseException {
IOContext ctxt = _createContext(data, true);
if (_inputDecorator != null) {
InputStream in = _inputDecorator.decorate(ctxt, data, 0, data.length);
if (in != null) {
return _create
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>Parser(in, ctxt);
}
}
return _createParser(data, 0, data.length, ctxt);
}
/**
* Method for constructing parser for parsing
* the contents of given byte array.
*
* @param data Buffer that contains data to parse
* @param offset Offset of the first data byte within buffer
* @param len Length of contents to parse within buffer
*
* @since 2.1
*/
public JsonParser createParser(byte[] data, int offset, int len) throws IOException, JsonParseException {
IOContext ctxt = _createContext(data, true);
// [JACKSON-512]: allow wrapping with InputDecorator
if (_inputDecorator != null) {
InputStream in = _inputDecorator.decorate(ctxt, data, offset, len);
if (in != null) {
return _createParser(in, ctxt);
}
}
return _createParser(data, offset, len, ctxt);
}
/**
* Method for constructing parser for parsing
* contents of given String.
*
* @since 2.1
*/
public JsonParser createParser(String content) throws IOException, JsonParseException {
final int strLen = content.length();
// Actually, let's use this for medium-sized content, up to 64kB chunk (32kb char)
if (_inputDecorator != null || strLen > 0x8000 || !canUseCharArrays()) {
// easier to just wrap in a Reader than extend InputDecorator; or, if content
// is too long for us to copy it over
return createParser(new StringReader(content));
}
IOContext ctxt = _createContext(content, true);
char[] buf = ctxt.allocTokenBuffer(strLen);
content.getChars(0, strLen, buf, 0);
return _createParser(buf, 0, strLen, ctxt, true);
}
/**
* Method for constructing parser for parsing
* contents of given char array.
*
* @since 2.4
*/
public JsonParser createParser(char[] content) throws IOException {
return createParser(content, 0, content.length);
}
/**
* Method for constructing parser for parsing contents of given char array.
*
* @since 2.4
*/
public JsonParser createParser(char
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>?), but should not
* matter a lot: performance penalty of extra wrapping is more
* relevant when accessing local file system.
*/
String host = url.getHost();
if (host == null || host.length() == 0) {
// [Issue#48]: Let's try to avoid probs with URL encoded stuff
String path = url.getPath();
if (path.indexOf('%') < 0) {
return new FileInputStream(url.getPath());
}
// otherwise, let's fall through and let URL decoder do its magic
}
}
return url.openStream();
}
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>outputMaxContiguous;
/**
* Intermediate buffer in which characters of a String are copied
* before being encoded.
*/
protected char[] _charBuffer;
/**
* Length of <code>_charBuffer</code>
*/
protected final int _charBufferLength;
/**
* 6 character temporary buffer allocated if needed, for constructing
* escape sequences
*/
protected byte[] _entityBuffer;
/**
* Flag that indicates whether the output buffer is recycable (and
* needs to be returned to recycler once we are done) or not.
*/
protected boolean _bufferRecyclable;
/*
/**********************************************************
/* Life-cycle
/**********************************************************
*/
public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec,
OutputStream out)
{
super(ctxt, features, codec);
_outputStream = out;
_bufferRecyclable = true;
_outputBuffer = ctxt.allocWriteEncodingBuffer();
_outputEnd = _outputBuffer.length;
/* To be exact, each char can take up to 6 bytes when escaped (Unicode
* escape with backslash, 'u' and 4 hex digits); but to avoid fluctuation,
* we will actually round down to only do up to 1/8 number of chars
*/
_outputMaxContiguous = _outputEnd >> 3;
_charBuffer = ctxt.allocConcatBuffer();
_charBufferLength = _charBuffer.length;
// By default we use this feature to determine additional quoting
if (isEnabled(Feature.ESCAPE_NON_ASCII)) {
setHighestNonEscapedChar(127);
}
}
public UTF8JsonGenerator(IOContext ctxt, int features, ObjectCodec codec,
OutputStream out,
byte[] outputBuffer, int outputOffset, boolean bufferRecyclable)
{
super(ctxt, features, codec);
_outputStream = out;
_bufferRecyclable = bufferRecyclable;
_outputTail = outputOffset;
_outputBuffer = outputBuffer;
_outputEnd = _outputBuffer.length;
// up to 6 bytes per char (see above), rounded up to 1/8
_outputMaxContiguous = (_outputEnd >> 3);
_charBuffer = ctxt.allocConcatBuffer();
_charBufferLength = _charBuffer.length;
}
/*
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> /**********************************************************
/* Overridden configuration methods
/**********************************************************
*/
@Override
public Object getOutputTarget() {
return _outputStream;
}
@Override
public int getOutputBuffered() {
// Assuming tail is always valid, set to 0 on close
return _outputTail;
}
/*
/**********************************************************
/* Overridden methods
/**********************************************************
*/
@Override
public void writeFieldName(String name) throws IOException
{
if (_cfgPrettyPrinter != null) {
_writePPFieldName(name);
return;
}
final int status = _writeContext.writeFieldName(name);
if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
_reportError("Can not write a field name, expecting a value");
}
if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) { // need comma
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_COMMA;
}
/* To support [JACKSON-46], we'll do this:
* (Question: should quoting of spaces (etc) still be enabled?)
*/
if (_cfgUnqNames) {
_writeStringSegments(name, false);
return;
}
final int len = name.length();
// Does it fit in buffer?
if (len > _charBufferLength) { // no, offline
_writeStringSegments(name, true);
return;
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
// But as one segment, or multiple?
if (len <= _outputMaxContiguous) {
if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
_flushBuffer();
}
_writeStringSegment(name, 0, len);
} else {
_writeStringSegments(name, 0, len);
}
// and closing quotes; need room for one more char:
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
}
@Override
public void writeFieldName(SerializableString name) throws IOException
{
if (_cfgPrettyPrinter != null) {
_writePPFieldName(name);
return;
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_RBRACKET;
}
_writeContext = _writeContext.clearAndGetParent();
}
@Override
public final void writeStartObject() throws IOException
{
_verifyValueWrite("start an object");
_writeContext = _writeContext.createChildObjectContext();
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeStartObject(this);
} else {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_LCURLY;
}
}
@Override
public final void writeEndObject() throws IOException
{
if (!_writeContext.inObject()) {
_reportError("Current context not an object but "+_writeContext.getTypeDesc());
}
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount());
} else {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_RCURLY;
}
_writeContext = _writeContext.clearAndGetParent();
}
/**
* Specialized version of <code>_writeFieldName</code>, off-lined
* to keep the "fast path" as simple (and hopefully fast) as possible.
*/
protected final void _writePPFieldName(String name) throws IOException
{
int status = _writeContext.writeFieldName(name);
if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
_reportError("Can not write a field name, expecting a value");
}
if ((status == JsonWriteContext.STATUS_OK_AFTER_COMMA)) {
_cfgPrettyPrinter.writeObjectEntrySeparator(this);
} else {
_cfgPrettyPrinter.beforeObjectEntries(this);
}
if (_cfgUnqNames) {
_writeStringSegments(name, false);
return;
}
final int len = name.length();
if (len > _charBufferLength) {
_writeStringSegments(name, true);
return;
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
name.getChars(0, len, _charBuffer, 0);
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> // But as one segment, or multiple?
if (len <= _outputMaxContiguous) {
if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
_flushBuffer();
}
_writeStringSegment(_charBuffer, 0, len);
} else {
_writeStringSegments(_charBuffer, 0, len);
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
}
protected final void _writePPFieldName(SerializableString name) throws IOException
{
final int status = _writeContext.writeFieldName(name.getValue());
if (status == JsonWriteContext.STATUS_EXPECT_VALUE) {
_reportError("Can not write a field name, expecting a value");
}
if (status == JsonWriteContext.STATUS_OK_AFTER_COMMA) {
_cfgPrettyPrinter.writeObjectEntrySeparator(this);
} else {
_cfgPrettyPrinter.beforeObjectEntries(this);
}
final boolean addQuotes = !_cfgUnqNames; // standard
if (addQuotes) {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
}
_writeBytes(name.asQuotedUTF8());
if (addQuotes) {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
}
}
/*
/**********************************************************
/* Output method implementations, textual
/**********************************************************
*/
@Override
public void writeString(String text) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (text == null) {
_writeNull();
return;
}
// First: if we can't guarantee it all fits, quoted, within output, offline
final int len = text.length();
if (len > _outputMaxContiguous) { // nope: off-line handling
_writeStringSegments(text, true);
return;
}
if ((_outputTail + len) >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
_writeStringSegment(text, 0, len); // we checked space already above
if (_outputTail >= _outputEnd) {
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
}
@Override
public void writeString(char[] text, int offset, int len) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
// One or multiple segments?
if (len <= _outputMaxContiguous) {
if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
_flushBuffer();
}
_writeStringSegment(text, offset, len);
} else {
_writeStringSegments(text, offset, len);
}
// And finally, closing quotes
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
}
@Override
public final void writeString(SerializableString text) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
int len = text.appendQuotedUTF8(_outputBuffer, _outputTail);
if (len < 0) {
_writeBytes(text.asQuotedUTF8());
} else {
_outputTail += len;
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
}
@Override
public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
_writeBytes(text, offset, length);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
}
@Override
public void writeUTF8String(byte[] text, int offset, int len) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
// One
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> or multiple segments?
if (len <= _outputMaxContiguous) {
_writeUTF8Segment(text, offset, len);
} else {
_writeUTF8Segments(text, offset, len);
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
}
/*
/**********************************************************
/* Output method implementations, unprocessed ("raw")
/**********************************************************
*/
@Override
public void writeRaw(String text) throws IOException {
final int len = text.length();
final char[] buf = _charBuffer;
if (len <= buf.length) {
text.getChars(0, len, buf, 0);
writeRaw(buf, 0, len);
} else {
writeRaw(text, 0, len);
}
}
@Override
public void writeRaw(String text, int offset, int len) throws IOException
{
final char[] buf = _charBuffer;
// minor optimization: see if we can just get and copy
if (len <= buf.length) {
text.getChars(offset, offset+len, buf, 0);
writeRaw(buf, 0, len);
return;
}
// If not, need segmented approach. For speed, let's also use input buffer
// size that is guaranteed to fit in output buffer; each char can expand to
// at most 3 bytes, so at most 1/3 of buffer size.
final int maxChunk = (_outputEnd >> 2) + (_outputEnd >> 4); // == (1/4 + 1/16) == 5/16
final int maxBytes = maxChunk * 3;
while (len > 0) {
int len2 = Math.min(maxChunk, len);
text.getChars(offset, offset+len2, buf, 0);
if ((_outputTail + maxBytes) > _outputEnd) {
_flushBuffer();
}
// If this is NOT the last segment and if the last character looks like
// split surrogate second half, drop it
if (len > 0) {
char ch = buf[len2-1];
if ((ch >= SURR1_FIRST) && (ch <= SURR1_LAST)) {
--len
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>2;
}
}
_writeRawSegment(buf, 0, len2);
offset += len2;
len -= len2;
}
}
@Override
public void writeRaw(SerializableString text) throws IOException
{
byte[] raw = text.asUnquotedUTF8();
if (raw.length > 0) {
_writeBytes(raw);
}
}
// since 2.5
@Override
public void writeRawValue(SerializableString text) throws IOException {
_verifyValueWrite(WRITE_RAW);
byte[] raw = text.asUnquotedUTF8();
if (raw.length > 0) {
_writeBytes(raw);
}
}
// @TODO: rewrite for speed...
@Override
public final void writeRaw(char[] cbuf, int offset, int len) throws IOException
{
// First: if we have 3 x charCount spaces, we know it'll fit just fine
{
int len3 = len+len+len;
if ((_outputTail + len3) > _outputEnd) {
// maybe we could flush?
if (_outputEnd < len3) { // wouldn't be enough...
_writeSegmentedRaw(cbuf, offset, len);
return;
}
// yes, flushing brings enough space
_flushBuffer();
}
}
len += offset; // now marks the end
// Note: here we know there is enough room, hence no output boundary checks
main_loop:
while (offset < len) {
inner_loop:
while (true) {
int ch = (int) cbuf[offset];
if (ch > 0x7F) {
break inner_loop;
}
_outputBuffer[_outputTail++] = (byte) ch;
if (++offset >= len) {
break main_loop;
}
}
char ch = cbuf[offset++];
if (ch < 0x800) { // 2-byte?
_outputBuffer[_outputTail++] = (byte) (0xc0 | (ch >> 6));
_outputBuffer[_outputTail++] = (byte) (0x80 | (ch & 0x3f));
} else {
offset = _outputRawMultiByteChar(ch, cbuf, offset, len);
}
}
}
@
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
return;
}
// What is the max length for floats?
_verifyValueWrite(WRITE_NUMBER);
writeRaw(String.valueOf(f));
}
@Override
public void writeNumber(BigDecimal value) throws IOException
{
// Don't really know max length for big decimal, no point checking
_verifyValueWrite(WRITE_NUMBER);
if (value == null) {
_writeNull();
} else if (_cfgNumbersAsStrings) {
_writeQuotedRaw(_asString(value));
} else {
writeRaw(_asString(value));
}
}
@Override
public void writeNumber(String encodedValue) throws IOException
{
_verifyValueWrite(WRITE_NUMBER);
if (_cfgNumbersAsStrings) {
_writeQuotedRaw(encodedValue);
} else {
writeRaw(encodedValue);
}
}
private final void _writeQuotedRaw(String value) throws IOException
{
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
writeRaw(value);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
}
@Override
public void writeBoolean(boolean state) throws IOException
{
_verifyValueWrite(WRITE_BOOLEAN);
if ((_outputTail + 5) >= _outputEnd) {
_flushBuffer();
}
byte[] keyword = state ? TRUE_BYTES : FALSE_BYTES;
int len = keyword.length;
System.arraycopy(keyword, 0, _outputBuffer, _outputTail, len);
_outputTail += len;
}
@Override
public void writeNull() throws IOException
{
_verifyValueWrite(WRITE_NULL);
_writeNull();
}
/*
/**********************************************************
/* Implementations for other methods
/**********************************************************
*/
@Override
protected final void _verifyValueWrite(String typeMsg) throws IOException
{
int status = _writeContext.writeValue();
if (status == JsonWriteContext.STATUS_EXPECT_NAME) {
_reportError("Can not "+typeMsg+", expecting field name");
}
if (_cfgPrettyPrinter == null) {
byte b;
switch (status) {
case JsonWriteContext.STATUS_OK_AFTER_COMMA:
b =
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> BYTE_COMMA;
break;
case JsonWriteContext.STATUS_OK_AFTER_COLON:
b = BYTE_COLON;
break;
case JsonWriteContext.STATUS_OK_AFTER_SPACE: // root-value separator
if (_rootValueSeparator != null) {
byte[] raw = _rootValueSeparator.asUnquotedUTF8();
if (raw.length > 0) {
_writeBytes(raw);
}
}
return;
case JsonWriteContext.STATUS_OK_AS_IS:
default:
return;
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail] = b;
++_outputTail;
return;
}
// Otherwise, pretty printer knows what to do...
_verifyPrettyValueWrite(typeMsg, status);
}
protected final void _verifyPrettyValueWrite(String typeMsg, int status) throws IOException
{
// If we have a pretty printer, it knows what to do:
switch (status) {
case JsonWriteContext.STATUS_OK_AFTER_COMMA: // array
_cfgPrettyPrinter.writeArrayValueSeparator(this);
break;
case JsonWriteContext.STATUS_OK_AFTER_COLON:
_cfgPrettyPrinter.writeObjectFieldValueSeparator(this);
break;
case JsonWriteContext.STATUS_OK_AFTER_SPACE:
_cfgPrettyPrinter.writeRootValueSeparator(this);
break;
case JsonWriteContext.STATUS_OK_AS_IS:
// First entry, but of which context?
if (_writeContext.inArray()) {
_cfgPrettyPrinter.beforeArrayValues(this);
} else if (_writeContext.inObject()) {
_cfgPrettyPrinter.beforeObjectEntries(this);
}
break;
default:
_throwInternal();
break;
}
}
/*
/**********************************************************
/* Low-level output handling
/**********************************************************
*/
@Override
public void flush() throws IOException
{
_flushBuffer();
if (_outputStream != null) {
if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) {
_outputStream.flush();
}
}
}
@Override
public void close() throws IOException
{
super.close();
/* 05-Dec-2008, tatu: To add [JACKSON
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>-27], need to close open
* scopes.
*/
// First: let's see that we still have buffers...
if ((_outputBuffer != null)
&& isEnabled(Feature.AUTO_CLOSE_JSON_CONTENT)) {
while (true) {
JsonStreamContext ctxt = getOutputContext();
if (ctxt.inArray()) {
writeEndArray();
} else if (ctxt.inObject()) {
writeEndObject();
} else {
break;
}
}
}
_flushBuffer();
_outputTail = 0; // just to ensure we don't think there's anything buffered
/* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
* on the underlying Reader, unless we "own" it, or auto-closing
* feature is enabled.
* One downside: when using UTF8Writer, underlying buffer(s)
* may not be properly recycled if we don't close the writer.
*/
if (_outputStream != null) {
if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_TARGET)) {
_outputStream.close();
} else if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) {
// If we can't close it, we should at least flush
_outputStream.flush();
}
}
// Internal buffer(s) generator has can now be released as well
_releaseBuffers();
}
@Override
protected void _releaseBuffers()
{
byte[] buf = _outputBuffer;
if (buf != null && _bufferRecyclable) {
_outputBuffer = null;
_ioContext.releaseWriteEncodingBuffer(buf);
}
char[] cbuf = _charBuffer;
if (cbuf != null) {
_charBuffer = null;
_ioContext.releaseConcatBuffer(cbuf);
}
}
/*
/**********************************************************
/* Internal methods, low-level writing, raw bytes
/**********************************************************
*/
private final void _writeBytes(byte[] bytes) throws IOException
{
final int len = bytes.length;
if ((_outputTail + len) > _outputEnd) {
_flushBuffer();
// still not enough?
if (len > MAX_BYTES_TO_BUFFER) {
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
_outputStream.write(bytes, 0, len);
return;
}
}
System.arraycopy(bytes, 0, _outputBuffer, _outputTail, len);
_outputTail += len;
}
private final void _writeBytes(byte[] bytes, int offset, int len) throws IOException
{
if ((_outputTail + len) > _outputEnd) {
_flushBuffer();
// still not enough?
if (len > MAX_BYTES_TO_BUFFER) {
_outputStream.write(bytes, offset, len);
return;
}
}
System.arraycopy(bytes, offset, _outputBuffer, _outputTail, len);
_outputTail += len;
}
/*
/**********************************************************
/* Internal methods, mid-level writing, String segments
/**********************************************************
*/
/**
* Method called when String to write is long enough not to fit
* completely in temporary copy buffer. If so, we will actually
* copy it in small enough chunks so it can be directly fed
* to single-segment writes (instead of maximum slices that
* would fit in copy buffer)
*/
private final void _writeStringSegments(String text, boolean addQuotes) throws IOException
{
if (addQuotes) {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
}
int left = text.length();
int offset = 0;
while (left > 0) {
int len = Math.min(_outputMaxContiguous, left);
if ((_outputTail + len) > _outputEnd) { // caller must ensure enough space
_flushBuffer();
}
_writeStringSegment(text, offset, len);
offset += len;
left -= len;
}
if (addQuotes) {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = BYTE_QUOTE;
}
}
/**
* Method called when character sequence to write is long enough that
* its maximum encoded and escaped form is not guaranteed to fit in
* the output buffer. If so, we will need to choose smaller output
* chunks to write at a time.
*/
private final void _writeStringSegments(char[] cbuf, int offset, int totalLen) throws IOException
{
do {
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>apes.getEscapeSequence(ch);
if (esc != null) {
outputPtr = _writeCustomEscape(outputBuffer, outputPtr, esc, end-offset);
continue;
}
if (ch <= 0x7FF) { // fine, just needs 2 byte output
outputBuffer[outputPtr++] = (byte) (0xc0 | (ch >> 6));
outputBuffer[outputPtr++] = (byte) (0x80 | (ch & 0x3f));
} else {
outputPtr = _outputMultiByteChar(ch, outputPtr);
}
}
_outputTail = outputPtr;
}
private final int _writeCustomEscape(byte[] outputBuffer, int outputPtr, SerializableString esc, int remainingChars)
throws IOException, JsonGenerationException
{
byte[] raw = esc.asUnquotedUTF8(); // must be escaped at this point, shouldn't double-quote
int len = raw.length;
if (len > 6) { // may violate constraints we have, do offline
return _handleLongCustomEscape(outputBuffer, outputPtr, _outputEnd, raw, remainingChars);
}
// otherwise will fit without issues, so:
System.arraycopy(raw, 0, outputBuffer, outputPtr, len);
return (outputPtr + len);
}
private final int _handleLongCustomEscape(byte[] outputBuffer, int outputPtr, int outputEnd, byte[] raw,
int remainingChars)
throws IOException, JsonGenerationException
{
int len = raw.length;
if ((outputPtr + len) > outputEnd) {
_outputTail = outputPtr;
_flushBuffer();
outputPtr = _outputTail;
if (len > outputBuffer.length) { // very unlikely, but possible...
_outputStream.write(raw, 0, len);
return outputPtr;
}
System.arraycopy(raw, 0, outputBuffer, outputPtr, len);
outputPtr += len;
}
// but is the invariant still obeyed? If not, flush once more
if ((outputPtr + 6 * remainingChars) > outputEnd) {
_flushBuffer();
return _outputTail;
}
return outputPtr;
}
/*
/**********************************************************
/* Internal methods, low-level writing, "raw UTF-8" segments
/**********************************************************
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>Tail++] = '\\';
_outputBuffer[_outputTail++] = 'n';
chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
}
}
// And then we may have 1 or 2 leftover bytes to encode
if (bytesLeft > 0) {
inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, bytesLeft);
inputPtr = 0;
if (inputEnd > 0) { // yes, but do we have room for output?
if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
_flushBuffer();
}
int b24 = ((int) readBuffer[inputPtr++]) << 16;
int amount;
if (inputPtr < inputEnd) {
b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
amount = 2;
} else {
amount = 1;
}
_outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
bytesLeft -= amount;
}
}
return bytesLeft;
}
// write method when length is unknown
protected final int _writeBinary(Base64Variant b64variant,
InputStream data, byte[] readBuffer)
throws IOException, JsonGenerationException
{
int inputPtr = 0;
int inputEnd = 0;
int lastFullOffset = -3;
int bytesDone = 0;
// Let's also reserve room for possible (and quoted) LF char each round
int safeOutputEnd = _outputEnd - 6;
int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
// Ok, first we loop through all full triplets of data:
while (true) {
if (inputPtr > lastFullOffset) { // need to load more
inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, readBuffer.length);
inputPtr = 0;
if (inputEnd < 3) { // required to try to read to have at least 3 bytes
break;
}
lastFullOffset = inputEnd-3;
}
if (_outputTail > safeOutputEnd) { // need to flush
_flushBuffer();
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
// First, mash 3 bytes into lsb of 32-bit int
int b24 = ((int) readBuffer[inputPtr++]) << 8;
b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
bytesDone += 3;
_outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
if (--chunksBeforeLF <= 0) {
_outputBuffer[_outputTail++] = '\\';
_outputBuffer[_outputTail++] = 'n';
chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
}
}
// And then we may have 1 or 2 leftover bytes to encode
if (inputPtr < inputEnd) { // yes, but do we have room for output?
if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
_flushBuffer();
}
int b24 = ((int) readBuffer[inputPtr++]) << 16;
int amount = 1;
if (inputPtr < inputEnd) {
b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
amount = 2;
}
bytesDone += amount;
_outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
}
return bytesDone;
}
private final int _readMore(InputStream in,
byte[] readBuffer, int inputPtr, int inputEnd,
int maxRead) throws IOException
{
// anything to shift to front?
int i = 0;
while (inputPtr < inputEnd) {
readBuffer[i++] = readBuffer[inputPtr++];
}
inputPtr = 0;
inputEnd = i;
maxRead = Math.min(maxRead, readBuffer.length);
do {
int length = maxRead - inputEnd;
if (length == 0) {
break;
}
int count = in.read(readBuffer, inputEnd, length);
if (count < 0) {
return inputEnd;
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> = 0;
_currBlockPtr = 0;
if (!_pastBlocks.isEmpty()) {
_pastBlocks.clear();
}
}
/**
* Clean up method to call to release all buffers this object may be
* using. After calling the method, no other accessors can be used (and
* attempt to do so may result in an exception)
*/
public void release() {
reset();
if (_bufferRecycler != null && _currBlock != null) {
_bufferRecycler.releaseByteBuffer(BufferRecycler.BYTE_WRITE_CONCAT_BUFFER, _currBlock);
_currBlock = null;
}
}
public void append(int i) {
if (_currBlockPtr >= _currBlock.length) {
_allocMore();
}
_currBlock[_currBlockPtr++] = (byte) i;
}
public void appendTwoBytes(int b16) {
if ((_currBlockPtr + 1) < _currBlock.length) {
_currBlock[_currBlockPtr++] = (byte) (b16 >> 8);
_currBlock[_currBlockPtr++] = (byte) b16;
} else {
append(b16 >> 8);
append(b16);
}
}
public void appendThreeBytes(int b24) {
if ((_currBlockPtr + 2) < _currBlock.length) {
_currBlock[_currBlockPtr++] = (byte) (b24 >> 16);
_currBlock[_currBlockPtr++] = (byte) (b24 >> 8);
_currBlock[_currBlockPtr++] = (byte) b24;
} else {
append(b24 >> 16);
append(b24 >> 8);
append(b24);
}
}
/**
* Method called when results are finalized and we can get the
* full aggregated result buffer to return to the caller
*/
public byte[] toByteArray()
{
int totalLen = _pastLen + _currBlockPtr;
if (totalLen == 0) { // quick check: nothing aggregated?
return NO_BYTES;
}
byte[] result = new byte[totalLen];
int offset = 0;
for (byte[] block : _pastBlocks) {
int len = block.length;
System
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>.arraycopy(block, 0, result, offset, len);
offset += len;
}
System.arraycopy(_currBlock, 0, result, offset, _currBlockPtr);
offset += _currBlockPtr;
if (offset != totalLen) { // just a sanity check
throw new RuntimeException("Internal error: total len assumed to be "+totalLen+", copied "+offset+" bytes");
}
// Let's only reset if there's sizable use, otherwise will get reset later on
if (!_pastBlocks.isEmpty()) {
reset();
}
return result;
}
/*
/**********************************************************
/* Non-stream API (similar to TextBuffer), since 1.6
/**********************************************************
*/
/**
* Method called when starting "manual" output: will clear out
* current state and return the first segment buffer to fill
*/
public byte[] resetAndGetFirstSegment() {
reset();
return _currBlock;
}
/**
* Method called when the current segment buffer is full; will
* append to current contents, allocate a new segment buffer
* and return it
*/
public byte[] finishCurrentSegment() {
_allocMore();
return _currBlock;
}
/**
* Method that will complete "manual" output process, coalesce
* content (if necessary) and return results as a contiguous buffer.
*
* @param lastBlockLength Amount of content in the current segment
* buffer.
*
* @return Coalesced contents
*/
public byte[] completeAndCoalesce(int lastBlockLength) {
_currBlockPtr = lastBlockLength;
return toByteArray();
}
public byte[] getCurrentSegment() { return _currBlock; }
public void setCurrentSegmentLength(int len) { _currBlockPtr = len; }
public int getCurrentSegmentLength() { return _currBlockPtr; }
/*
/**********************************************************
/* OutputStream implementation
/**********************************************************
*/
@Override
public void write(byte[] b) {
write(b, 0, b.length);
}
@Override
public void write(byte[] b, int off, int len)
{
while (true) {
int max = _currBlock.length - _currBlockPtr;
int toCopy = Math.min(max, len);
if (toCopy > 0) {
System.arraycopy(b, off, _
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>currBlock, _currBlockPtr, toCopy);
off += toCopy;
_currBlockPtr += toCopy;
len -= toCopy;
}
if (len <= 0) break;
_allocMore();
}
}
@Override
public void write(int b) {
append(b);
}
@Override public void close() { /* NOP */ }
@Override public void flush() { /* NOP */ }
/*
/**********************************************************
/* Internal methods
/**********************************************************
*/
private void _allocMore()
{
_pastLen += _currBlock.length;
/* Let's allocate block that's half the total size, except
* never smaller than twice the initial block size.
* The idea is just to grow with reasonable rate, to optimize
* between minimal number of chunks and minimal amount of
* wasted space.
*/
int newSize = Math.max((_pastLen >> 1), (INITIAL_BLOCK_SIZE + INITIAL_BLOCK_SIZE));
// plus not to exceed max we define...
if (newSize > MAX_BLOCK_SIZE) {
newSize = MAX_BLOCK_SIZE;
}
_pastBlocks.add(_currBlock);
_currBlock = new byte[newSize];
_currBlockPtr = 0;
}
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>package com.fasterxml.jackson.core.io;
import java.util.Arrays;
public final class CharTypes
{
private final static char[] HC = "0123456789ABCDEF".toCharArray();
private final static byte[] HB;
static {
int len = HC.length;
HB = new byte[len];
for (int i = 0; i < len; ++i) {
HB[i] = (byte) HC[i];
}
}
/**
* Lookup table used for determining which input characters
* need special handling when contained in text segment.
*/
private final static int[] sInputCodes;
static {
/* 96 would do for most cases (backslash is ASCII 94)
* but if we want to do lookups by raw bytes it's better
* to have full table
*/
final int[] table = new int[256];
// Control chars and non-space white space are not allowed unquoted
for (int i = 0; i < 32; ++i) {
table[i] = -1;
}
// And then string end and quote markers are special too
table['"'] = 1;
table['\\'] = 1;
sInputCodes = table;
}
/**
* Additionally we can combine UTF-8 decoding info into similar
* data table.
*/
private final static int[] sInputCodesUTF8;
static {
final int[] table = new int[sInputCodes.length];
System.arraycopy(sInputCodes, 0, table, 0, table.length);
for (int c = 128; c < 256; ++c) {
int code;
// We'll add number of bytes needed for decoding
if ((c & 0xE0) == 0xC0) { // 2 bytes (0x0080 - 0x07FF)
code = 2;
} else if ((c & 0xF0) == 0xE0) { // 3 bytes (0x0800 - 0xFFFF)
code = 3;
} else if ((c & 0xF8) == 0xF0) {
// 4 bytes; double-char with surrogates and all...
code = 4
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>;
} else {
// And -1 seems like a good "universal" error marker...
code = -1;
}
table[c] = code;
}
sInputCodesUTF8 = table;
}
/**
* To support non-default (and -standard) unquoted field names mode,
* need to have alternate checking.
* Basically this is list of 8-bit ASCII characters that are legal
* as part of Javascript identifier
*/
private final static int[] sInputCodesJsNames;
static {
final int[] table = new int[256];
// Default is "not a name char", mark ones that are
Arrays.fill(table, -1);
// Assume rules with JS same as Java (change if/as needed)
for (int i = 33; i < 256; ++i) {
if (Character.isJavaIdentifierPart((char) i)) {
table[i] = 0;
}
}
/* As per [JACKSON-267], '@', '#' and '*' are also to be accepted as well.
* And '-' (for hyphenated names); and '+' for sake of symmetricity...
*/
table['@'] = 0;
table['#'] = 0;
table['*'] = 0;
table['-'] = 0;
table['+'] = 0;
sInputCodesJsNames = table;
}
/**
* This table is similar to Latin-1, except that it marks all "high-bit"
* code as ok. They will be validated at a later point, when decoding
* name
*/
private final static int[] sInputCodesUtf8JsNames;
static {
final int[] table = new int[256];
// start with 8-bit JS names
System.arraycopy(sInputCodesJsNames, 0, table, 0, table.length);
Arrays.fill(table, 128, 128, 0);
sInputCodesUtf8JsNames = table;
}
/**
* Decoding table used to quickly determine characters that are
* relevant within comment content.
*/
private final static int[] sInputCodesComment;
static {
final int[] buf = new int[256];
// but first: let's start with
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> }
public static int charToHex(int ch)
{
return (ch > 127) ? -1 : sHexValues[ch];
}
public static void appendQuoted(StringBuilder sb, String content)
{
final int[] escCodes = sOutputEscapes128;
int escLen = escCodes.length;
for (int i = 0, len = content.length(); i < len; ++i) {
char c = content.charAt(i);
if (c >= escLen || escCodes[c] == 0) {
sb.append(c);
continue;
}
sb.append('\\');
int escCode = escCodes[c];
if (escCode < 0) { // generic quoting (hex value)
// The only negative value sOutputEscapes128 returns
// is CharacterEscapes.ESCAPE_STANDARD, which mean
// appendQuotes should encode using the Unicode encoding;
// not sure if this is the right way to encode for
// CharacterEscapes.ESCAPE_CUSTOM or other (future)
// CharacterEscapes.ESCAPE_XXX values.
// We know that it has to fit in just 2 hex chars
sb.append('u');
sb.append('0');
sb.append('0');
int value = c; // widening
sb.append(HC[value >> 4]);
sb.append(HC[value & 0xF]);
} else { // "named", i.e. prepend with slash
sb.append((char) escCode);
}
}
}
public static char[] copyHexChars() {
return (char[]) HC.clone();
}
public static byte[] copyHexBytes() {
return (byte[]) HB.clone();
}
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> return new JsonParseException(this, msg, t);
}
protected static byte[] _asciiBytes(String str) {
byte[] b = new byte[str.length()];
for (int i = 0, len = str.length(); i < len; ++i) {
b[i] = (byte) str.charAt(i);
}
return b;
}
protected static String _ascii(byte[] b) {
try {
return new String(b, "US-ASCII");
} catch (IOException e) { // never occurs
throw new RuntimeException(e);
}
}
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> to calc for powers of two.
_indexMask = initialSize - 1;
_size = 0;
_longestCollisionList = 0;
// Hard-coded fill factor is 75%
_sizeThreshold = _thresholdSize(initialSize);
}
private static int _thresholdSize(int hashAreaSize) { return hashAreaSize - (hashAreaSize >> 2); }
/**
* Internal constructor used when creating child instances.
*/
private CharsToNameCanonicalizer(CharsToNameCanonicalizer parent, int flags,
String[] symbols, Bucket[] buckets, int size, int hashSeed, int longestColl) {
_parent = parent;
_flags = flags;
_canonicalize = JsonFactory.Feature.CANONICALIZE_FIELD_NAMES.enabledIn(flags);
_symbols = symbols;
_buckets = buckets;
_size = size;
_hashSeed = hashSeed;
// Hard-coded fill factor, 75%
int arrayLen = (symbols.length);
_sizeThreshold = _thresholdSize(arrayLen);
_indexMask = (arrayLen - 1);
_longestCollisionList = longestColl;
// Need to make copies of arrays, if/when adding new entries
_dirty = false;
}
/**
* "Factory" method; will create a new child instance of this symbol
* table. It will be a copy-on-write instance, ie. it will only use
* read-only copy of parent's data, but when changes are needed, a
* copy will be created.
*<p>
* Note: while this method is synchronized, it is generally not
* safe to both use makeChild/mergeChild, AND to use instance
* actively. Instead, a separate 'root' instance should be used
* on which only makeChild/mergeChild are called, but instance itself
* is not used as a symbol table.
*/
public CharsToNameCanonicalizer makeChild(int flags) {
/* 24-Jul-2012, tatu: Trying to reduce scope of synchronization, assuming
* that synchronizing construction is the (potentially) expensive part,
* and not so much short copy-the-variables thing.
*/
final String[] symbols;
final Bucket[] buckets;
final int size;
final int hashSeed;
final int longest
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>sizeThreshold;
_indexMask = child._indexMask;
_longestCollisionList = child._longestCollisionList;
// Dirty flag... well, let's just clear it. Shouldn't really matter for master tables
// (which this is, given something is merged to it)
_dirty = false;
}
}
}
public void release(){
// If nothing has been added, nothing to do
if (!maybeDirty()) { return; }
if (_parent != null && _canonicalize) { // canonicalize set to false if max size was reached
_parent.mergeChild(this);
/* Let's also mark this instance as dirty, so that just in
* case release was too early, there's no corruption
* of possibly shared data.
*/
_dirty = false;
}
}
/*
/**********************************************************
/* Public API, generic accessors:
/**********************************************************
*/
public int size() { return _size; }
/**
* Method for checking number of primary hash buckets this symbol
* table uses.
*
* @since 2.1
*/
public int bucketCount() { return _symbols.length; }
public boolean maybeDirty() { return _dirty; }
public int hashSeed() { return _hashSeed; }
/**
* Method mostly needed by unit tests; calculates number of
* entries that are in collision list. Value can be at most
* ({@link #size} - 1), but should usually be much lower, ideally 0.
*
* @since 2.1
*/
public int collisionCount() {
int count = 0;
for (Bucket bucket : _buckets) {
if (bucket != null) {
count += bucket.length;
}
}
return count;
}
/**
* Method mostly needed by unit tests; calculates length of the
* longest collision chain. This should typically be a low number,
* but may be up to {@link #size} - 1 in the pathological case
*
* @since 2.1
*/
public int maxCollisionLength() { return _longestCollisionList; }
/*
/**********************************************************
/* Public API, accessing symbols:
/**********************************************************
*/
public String findSymbol(char[] buffer, int start, int len, int h)
{
if (len < 1) { // empty Strings are simplest
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> to handle up front
return "";
}
if (!_canonicalize) { // [JACKSON-259]
return new String(buffer, start, len);
}
/* Related to problems with sub-standard hashing (somewhat
* relevant for collision attacks too), let's try little
* bit of shuffling to improve hash codes.
* (note, however, that this can't help with full collisions)
*/
int index = _hashToIndex(h);
String sym = _symbols[index];
// Optimal case; checking existing primary symbol for hash index:
if (sym != null) {
// Let's inline primary String equality checking:
if (sym.length() == len) {
int i = 0;
while (sym.charAt(i) == buffer[start+i]) {
// Optimal case; primary match found
if (++i == len) {
return sym;
}
}
}
Bucket b = _buckets[index>>1];
if (b != null) {
sym = b.has(buffer, start, len);
if (sym != null) {
return sym;
}
sym = _findSymbol2(buffer, start, len, b.next);
if (sym != null) {
return sym;
}
}
}
return _addSymbol(buffer, start, len, h, index);
}
private String _findSymbol2(char[] buffer, int start, int len, Bucket b) {
while (b != null) {
String sym = b.has(buffer, start, len);
if (sym != null) {
return sym;
}
b = b.next;
}
return null;
}
private String _addSymbol(char[] buffer, int start, int len, int h, int index)
{
if (!_dirty) { //need to do copy-on-write?
copyArrays();
_dirty = true;
} else if (_size >= _sizeThreshold) { // Need to expand?
rehash();
/* Need to recalc hash; rare occurence (index mask has been
* recalculated as part of rehash)
*/
index = _hashToIndex(calcHash(buffer, start, len));
}
String newSymbol = new String(buffer, start, len);
if (JsonFactory.Feature.INTER
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>N_FIELD_NAMES.enabledIn(_flags)) {
newSymbol = InternCache.instance.intern(newSymbol);
}
++_size;
// Ok; do we need to add primary entry, or a bucket?
if (_symbols[index] == null) {
_symbols[index] = newSymbol;
} else {
final int bix = (index >> 1);
Bucket newB = new Bucket(newSymbol, _buckets[bix]);
int collLen = newB.length;
if (collLen > MAX_COLL_CHAIN_LENGTH) {
/* 23-May-2014, tatu: Instead of throwing an exception right away, let's handle
* in bit smarter way.
*/
_handleSpillOverflow(bix, newB);
} else {
_buckets[bix] = newB;
_longestCollisionList = Math.max(collLen, _longestCollisionList);
}
}
return newSymbol;
}
private void _handleSpillOverflow(int bindex, Bucket newBucket)
{
if (_overflows == null) {
_overflows = new BitSet();
_overflows.set(bindex);
} else {
if (_overflows.get(bindex)) {
// Has happened once already, so not a coincident...
if (JsonFactory.Feature.FAIL_ON_SYMBOL_HASH_OVERFLOW.enabledIn(_flags)) {
reportTooManyCollisions(MAX_COLL_CHAIN_LENGTH);
}
// but even if we don't fail, we will stop canonicalizing:
_canonicalize = false;
} else {
_overflows.set(bindex);
}
}
// regardless, if we get this far, clear up the bucket, adjust size appropriately.
_symbols[bindex + bindex] = newBucket.symbol;
_buckets[bindex] = null;
// newBucket contains new symbol; but we wil
_size -= (newBucket.length);
// we could calculate longest; but for now just mark as invalid
_longestCollisionList = -1;
}
/**
* Helper method that takes in a "raw" hash value, shuffles it as necessary,
* and truncates to be used as the index.
*/
public int _hashToIndex(int rawHash
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>) {
// doing these seems to help a bit
rawHash += (rawHash >>> 15);
rawHash ^= (rawHash << 7);
rawHash += (rawHash >>> 3);
return (rawHash & _indexMask);
}
/**
* Implementation of a hashing method for variable length
* Strings. Most of the time intention is that this calculation
* is done by caller during parsing, not here; however, sometimes
* it needs to be done for parsed "String" too.
*
* @param len Length of String; has to be at least 1 (caller guarantees
* this pre-condition)
*/
public int calcHash(char[] buffer, int start, int len) {
int hash = _hashSeed;
for (int i = start, end = start+len; i < end; ++i) {
hash = (hash * HASH_MULT) + (int) buffer[i];
}
// NOTE: shuffling, if any, is done in 'findSymbol()', not here:
return (hash == 0) ? 1 : hash;
}
public int calcHash(String key)
{
final int len = key.length();
int hash = _hashSeed;
for (int i = 0; i < len; ++i) {
hash = (hash * HASH_MULT) + (int) key.charAt(i);
}
// NOTE: shuffling, if any, is done in 'findSymbol()', not here:
return (hash == 0) ? 1 : hash;
}
/*
/**********************************************************
/* Internal methods
/**********************************************************
*/
/**
* Method called when copy-on-write is needed; generally when first
* change is made to a derived symbol table.
*/
private void copyArrays() {
final String[] oldSyms = _symbols;
_symbols = Arrays.copyOf(oldSyms, oldSyms.length);
final Bucket[] oldBuckets = _buckets;
_buckets = Arrays.copyOf(oldBuckets, oldBuckets.length);
}
/**
* Method called when size (number of entries) of symbol table grows
* so big that load factor is exceeded. Since size has to remain
* power of two, arrays will then always be doubled. Main work
* is really redistributing old entries into new String/Bucket
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
* entries.
*/
private void rehash() {
int size = _symbols.length;
int newSize = size + size;
/* 12-Mar-2010, tatu: Let's actually limit maximum size we are
* prepared to use, to guard against OOME in case of unbounded
* name sets (unique [non-repeating] names)
*/
if (newSize > MAX_T_SIZE) {
/* If this happens, there's no point in either growing or shrinking hash areas.
* Rather, let's just cut our losses and stop canonicalizing.
*/
_size = 0;
_canonicalize = false;
// in theory, could just leave these as null, but...
_symbols = new String[DEFAULT_T_SIZE];
_buckets = new Bucket[DEFAULT_T_SIZE>>1];
_indexMask = DEFAULT_T_SIZE-1;
_dirty = true;
return;
}
String[] oldSyms = _symbols;
Bucket[] oldBuckets = _buckets;
_symbols = new String[newSize];
_buckets = new Bucket[newSize >> 1];
// Let's update index mask, threshold, now (needed for rehashing)
_indexMask = newSize - 1;
_sizeThreshold = _thresholdSize(newSize);
int count = 0; // let's do sanity check
/* Need to do two loops, unfortunately, since spill-over area is
* only half the size:
*/
int maxColl = 0;
for (int i = 0; i < size; ++i) {
String symbol = oldSyms[i];
if (symbol != null) {
++count;
int index = _hashToIndex(calcHash(symbol));
if (_symbols[index] == null) {
_symbols[index] = symbol;
} else {
int bix = (index >> 1);
Bucket newB = new Bucket(symbol, _buckets[bix]);
_buckets[bix] = newB;
maxColl = Math.max(maxColl, newB.length);
}
}
}
size >>= 1;
for (int i = 0; i < size; ++i) {
Bucket b = oldBuckets[i];
while (b !=
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> null) {
++count;
String symbol = b.symbol;
int index = _hashToIndex(calcHash(symbol));
if (_symbols[index] == null) {
_symbols[index] = symbol;
} else {
int bix = (index >> 1);
Bucket newB = new Bucket(symbol, _buckets[bix]);
_buckets[bix] = newB;
maxColl = Math.max(maxColl, newB.length);
}
b = b.next;
}
}
_longestCollisionList = maxColl;
_overflows = null;
if (count != _size) {
throw new Error("Internal error on SymbolTable.rehash(): had "+_size+" entries; now have "+count+".");
}
}
/**
* @since 2.1
*/
protected void reportTooManyCollisions(int maxLen) {
throw new IllegalStateException("Longest collision chain in symbol table (of size "+_size
+") now exceeds maximum, "+maxLen+" -- suspect a DoS attack based on hash collisions");
}
// For debugging, comment out
/*
@Override
public String toString()
{
StringBuilder sb = new StringBuilder();
int primaryCount = 0;
for (String s : _symbols) {
if (s != null) ++primaryCount;
}
sb.append("[BytesToNameCanonicalizer, size: ");
sb.append(_size);
sb.append('/');
sb.append(_symbols.length);
sb.append(", ");
sb.append(primaryCount);
sb.append('/');
sb.append(_size - primaryCount);
sb.append(" coll; avg length: ");
// Average length: minimum of 1 for all (1 == primary hit);
// and then 1 per each traversal for collisions/buckets
//int maxDist = 1;
int pathCount = _size;
for (Bucket b : _buckets) {
if (b != null) {
int spillLen = b.length;
for (int j = 1; j <= spillLen; ++j) {
pathCount += j;
}
}
}
double avgLength;
if (_size == 0) {
avgLength = 0.0;
} else {
avgLength = (double) pathCount / (double) _size
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>;
}
// let's round up a bit (two 2 decimal places)
//avgLength -= (avgLength % 0.01);
sb.append(avgLength);
sb.append(']');
return sb.toString();
}
*/
/*
/**********************************************************
/* Bucket class
/**********************************************************
*/
/**
* This class is a symbol table entry. Each entry acts as a node
* in a linked list.
*/
static final class Bucket
{
public final String symbol;
public final Bucket next;
public final int length;
public Bucket(String s, Bucket n) {
symbol = s;
next = n;
length = (n == null) ? 1 : n.length+1;
}
public String has(char[] buf, int start, int len) {
if (symbol.length() != len) {
return null;
}
int i = 0;
do {
if (symbol.charAt(i) != buf[start+i]) {
return null;
}
} while (++i < len);
return symbol;
}
}
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>package com.fasterxml.jackson.core.json;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.core.io.*;
/**
* {@link JsonGenerator} that outputs JSON content using a {@link java.io.Writer}
* which handles character encoding.
*/
public final class WriterBasedJsonGenerator
extends JsonGeneratorImpl
{
final protected static int SHORT_WRITE = 32;
final protected static char[] HEX_CHARS = CharTypes.copyHexChars();
/*
/**********************************************************
/* Output buffering
/**********************************************************
*/
final protected Writer _writer;
/**
* Intermediate buffer in which contents are buffered before
* being written using {@link #_writer}.
*/
protected char[] _outputBuffer;
/**
* Pointer to the first buffered character to output
*/
protected int _outputHead;
/**
* Pointer to the position right beyond the last character to output
* (end marker; may point to position right beyond the end of the buffer)
*/
protected int _outputTail;
/**
* End marker of the output buffer; one past the last valid position
* within the buffer.
*/
protected int _outputEnd;
/**
* Short (14 char) temporary buffer allocated if needed, for constructing
* escape sequences
*/
protected char[] _entityBuffer;
/**
* When custom escapes are used, this member variable is used
* internally to hold a reference to currently used escape
*/
protected SerializableString _currentEscape;
/*
/**********************************************************
/* Life-cycle
/**********************************************************
*/
public WriterBasedJsonGenerator(IOContext ctxt, int features,
ObjectCodec codec, Writer w)
{
super(ctxt, features, codec);
_writer = w;
_outputBuffer = ctxt.allocConcatBuffer();
_outputEnd = _outputBuffer.length;
}
/*
/**********************************************************
/* Overridden configuration methods
/**********************************************************
*/
@Override
public Object getOutputTarget() {
return _writer;
}
@Override
public int getOutputBuffered() {
// Assuming tail and head are kept but... trust and verify:
int len = _outputTail - _outputHead;
return Math.max(0, len);
}
/*
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>[_outputTail++] = ',';
}
// Alternate mode, in which quoting of field names disabled?
final char[] quoted = name.asQuotedChars();
if (_cfgUnqNames) {
writeRaw(quoted, 0, quoted.length);
return;
}
// we know there's room for at least one more char
_outputBuffer[_outputTail++] = '"';
// The beef:
final int qlen = quoted.length;
if ((_outputTail + qlen + 1) >= _outputEnd) {
writeRaw(quoted, 0, qlen);
// and closing quotes; need room for one more char:
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"';
} else {
System.arraycopy(quoted, 0, _outputBuffer, _outputTail, qlen);
_outputTail += qlen;
_outputBuffer[_outputTail++] = '"';
}
}
/*
/**********************************************************
/* Output method implementations, structural
/**********************************************************
*/
@Override
public void writeStartArray() throws IOException, JsonGenerationException
{
_verifyValueWrite("start an array");
_writeContext = _writeContext.createChildArrayContext();
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeStartArray(this);
} else {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '[';
}
}
@Override
public void writeEndArray() throws IOException, JsonGenerationException
{
if (!_writeContext.inArray()) {
_reportError("Current context not an ARRAY but "+_writeContext.getTypeDesc());
}
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeEndArray(this, _writeContext.getEntryCount());
} else {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = ']';
}
_writeContext = _writeContext.clearAndGetParent();
}
@Override
public void writeStartObject() throws IOException, JsonGenerationException
{
_verifyValueWrite("start an object");
_writeContext = _writeContext.createChildObjectContext();
if (_cfgPrettyPrinter != null) {
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> _cfgPrettyPrinter.writeStartObject(this);
} else {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '{';
}
}
@Override
public void writeEndObject() throws IOException, JsonGenerationException
{
if (!_writeContext.inObject()) {
_reportError("Current context not an object but "+_writeContext.getTypeDesc());
}
if (_cfgPrettyPrinter != null) {
_cfgPrettyPrinter.writeEndObject(this, _writeContext.getEntryCount());
} else {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '}';
}
_writeContext = _writeContext.clearAndGetParent();
}
/**
* Specialized version of <code>_writeFieldName</code>, off-lined
* to keep the "fast path" as simple (and hopefully fast) as possible.
*/
protected void _writePPFieldName(String name, boolean commaBefore) throws IOException
{
if (commaBefore) {
_cfgPrettyPrinter.writeObjectEntrySeparator(this);
} else {
_cfgPrettyPrinter.beforeObjectEntries(this);
}
if (_cfgUnqNames) {// non-standard, omit quotes
_writeString(name);
} else {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"';
_writeString(name);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"';
}
}
protected void _writePPFieldName(SerializableString name, boolean commaBefore) throws IOException
{
if (commaBefore) {
_cfgPrettyPrinter.writeObjectEntrySeparator(this);
} else {
_cfgPrettyPrinter.beforeObjectEntries(this);
}
final char[] quoted = name.asQuotedChars();
if (_cfgUnqNames) {// non-standard, omit quotes
writeRaw(quoted, 0, quoted.length);
} else {
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"';
writeRaw(quoted, 0, quoted.length);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>[_outputTail++] = '"';
}
}
/*
/**********************************************************
/* Output method implementations, textual
/**********************************************************
*/
@Override
public void writeString(String text) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (text == null) {
_writeNull();
return;
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"';
_writeString(text);
// And finally, closing quotes
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"';
}
@Override
public void writeString(char[] text, int offset, int len) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"';
_writeString(text, offset, len);
// And finally, closing quotes
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"';
}
@Override
public void writeString(SerializableString sstr) throws IOException
{
_verifyValueWrite(WRITE_STRING);
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"';
// Note: copied from writeRaw:
char[] text = sstr.asQuotedChars();
final int len = text.length;
// Only worth buffering if it's a short write?
if (len < SHORT_WRITE) {
int room = _outputEnd - _outputTail;
if (len > room) {
_flushBuffer();
}
System.arraycopy(text, 0, _outputBuffer, _outputTail, len);
_outputTail += len;
} else {
// Otherwise, better just pass through:
_flushBuffer();
_writer.write(text, 0, len);
}
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"';
}
@Override
public void writeRawUTF8String(byte[] text, int offset, int length) throws IOException {
// could add support for buffering if we really want
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> it...
_reportUnsupportedOperation();
}
@Override
public void writeUTF8String(byte[] text, int offset, int length) throws IOException {
// could add support for buffering if we really want it...
_reportUnsupportedOperation();
}
/*
/**********************************************************
/* Output method implementations, unprocessed ("raw")
/**********************************************************
*/
@Override
public void writeRaw(String text) throws IOException
{
// Nothing to check, can just output as is
int len = text.length();
int room = _outputEnd - _outputTail;
if (room == 0) {
_flushBuffer();
room = _outputEnd - _outputTail;
}
// But would it nicely fit in? If yes, it's easy
if (room >= len) {
text.getChars(0, len, _outputBuffer, _outputTail);
_outputTail += len;
} else {
writeRawLong(text);
}
}
@Override
public void writeRaw(String text, int start, int len) throws IOException
{
// Nothing to check, can just output as is
int room = _outputEnd - _outputTail;
if (room < len) {
_flushBuffer();
room = _outputEnd - _outputTail;
}
// But would it nicely fit in? If yes, it's easy
if (room >= len) {
text.getChars(start, start+len, _outputBuffer, _outputTail);
_outputTail += len;
} else {
writeRawLong(text.substring(start, start+len));
}
}
// @since 2.1
@Override
public void writeRaw(SerializableString text) throws IOException {
writeRaw(text.getValue());
}
@Override
public void writeRaw(char[] text, int offset, int len) throws IOException
{
// Only worth buffering if it's a short write?
if (len < SHORT_WRITE) {
int room = _outputEnd - _outputTail;
if (len > room) {
_flushBuffer();
}
System.arraycopy(text, offset, _outputBuffer, _outputTail, len);
_outputTail += len;
return;
}
// Otherwise, better just pass through:
_flushBuffer();
_writer.write(text, offset
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>, len);
}
@Override
public void writeRaw(char c) throws IOException
{
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = c;
}
private void writeRawLong(String text) throws IOException
{
int room = _outputEnd - _outputTail;
// If not, need to do it by looping
text.getChars(0, room, _outputBuffer, _outputTail);
_outputTail += room;
_flushBuffer();
int offset = room;
int len = text.length() - room;
while (len > _outputEnd) {
int amount = _outputEnd;
text.getChars(offset, offset+amount, _outputBuffer, 0);
_outputHead = 0;
_outputTail = amount;
_flushBuffer();
offset += amount;
len -= amount;
}
// And last piece (at most length of buffer)
text.getChars(offset, offset+len, _outputBuffer, 0);
_outputHead = 0;
_outputTail = len;
}
/*
/**********************************************************
/* Output method implementations, base64-encoded binary
/**********************************************************
*/
@Override
public void writeBinary(Base64Variant b64variant, byte[] data, int offset, int len)
throws IOException, JsonGenerationException
{
_verifyValueWrite(WRITE_BINARY);
// Starting quotes
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"';
_writeBinary(b64variant, data, offset, offset+len);
// and closing quotes
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"';
}
@Override
public int writeBinary(Base64Variant b64variant,
InputStream data, int dataLength)
throws IOException, JsonGenerationException
{
_verifyValueWrite(WRITE_BINARY);
// Starting quotes
if (_outputTail >= _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '"';
byte[] encodingBuffer = _ioContext.allocBase64Buffer();
int bytes;
try {
if (dataLength < 0) { // length
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
@Override
public void close() throws IOException
{
super.close();
/* 05-Dec-2008, tatu: To add [JACKSON-27], need to close open
* scopes.
*/
// First: let's see that we still have buffers...
if (_outputBuffer != null
&& isEnabled(Feature.AUTO_CLOSE_JSON_CONTENT)) {
while (true) {
JsonStreamContext ctxt = getOutputContext();
if (ctxt.inArray()) {
writeEndArray();
} else if (ctxt.inObject()) {
writeEndObject();
} else {
break;
}
}
}
_flushBuffer();
_outputHead = 0;
_outputTail = 0;
/* 25-Nov-2008, tatus: As per [JACKSON-16] we are not to call close()
* on the underlying Reader, unless we "own" it, or auto-closing
* feature is enabled.
* One downside: when using UTF8Writer, underlying buffer(s)
* may not be properly recycled if we don't close the writer.
*/
if (_writer != null) {
if (_ioContext.isResourceManaged() || isEnabled(Feature.AUTO_CLOSE_TARGET)) {
_writer.close();
} else if (isEnabled(Feature.FLUSH_PASSED_TO_STREAM)) {
// If we can't close it, we should at least flush
_writer.flush();
}
}
// Internal buffer(s) generator has can now be released as well
_releaseBuffers();
}
@Override
protected void _releaseBuffers()
{
char[] buf = _outputBuffer;
if (buf != null) {
_outputBuffer = null;
_ioContext.releaseConcatBuffer(buf);
}
}
/*
/**********************************************************
/* Internal methods, low-level writing; text, default
/**********************************************************
*/
private void _writeString(String text) throws IOException
{
/* One check first: if String won't fit in the buffer, let's
* segment writes. No point in extending buffer to huge sizes
* (like if someone wants to include multi-megabyte base64
* encoded stuff or such)
*/
final int len = text.length();
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> if (len > _outputEnd) { // Let's reserve space for entity at begin/end
_writeLongString(text);
return;
}
// Ok: we know String will fit in buffer ok
// But do we need to flush first?
if ((_outputTail + len) > _outputEnd) {
_flushBuffer();
}
text.getChars(0, len, _outputBuffer, _outputTail);
if (_characterEscapes != null) {
_writeStringCustom(len);
} else if (_maximumNonEscapedChar != 0) {
_writeStringASCII(len, _maximumNonEscapedChar);
} else {
_writeString2(len);
}
}
private void _writeString2(final int len) throws IOException
{
// And then we'll need to verify need for escaping etc:
final int end = _outputTail + len;
final int[] escCodes = _outputEscapes;
final int escLen = escCodes.length;
output_loop:
while (_outputTail < end) {
// Fast loop for chars not needing escaping
escape_loop:
while (true) {
char c = _outputBuffer[_outputTail];
if (c < escLen && escCodes[c] != 0) {
break escape_loop;
}
if (++_outputTail >= end) {
break output_loop;
}
}
// Ok, bumped into something that needs escaping.
/* First things first: need to flush the buffer.
* Inlined, as we don't want to lose tail pointer
*/
int flushLen = (_outputTail - _outputHead);
if (flushLen > 0) {
_writer.write(_outputBuffer, _outputHead, flushLen);
}
/* In any case, tail will be the new start, so hopefully
* we have room now.
*/
char c = _outputBuffer[_outputTail++];
_prependOrWriteCharacterEscape(c, escCodes[c]);
}
}
/**
* Method called to write "long strings", strings whose length exceeds
* output buffer length.
*/
private void _writeLongString(String text) throws IOException
{
// First things first: let's flush the buffer to get some more room
_flushBuffer();
// Then we can write
final int textLen = text.length();
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> int offset = 0;
do {
int max = _outputEnd;
int segmentLen = ((offset + max) > textLen)
? (textLen - offset) : max;
text.getChars(offset, offset+segmentLen, _outputBuffer, 0);
if (_characterEscapes != null) {
_writeSegmentCustom(segmentLen);
} else if (_maximumNonEscapedChar != 0) {
_writeSegmentASCII(segmentLen, _maximumNonEscapedChar);
} else {
_writeSegment(segmentLen);
}
offset += segmentLen;
} while (offset < textLen);
}
/**
* Method called to output textual context which has been copied
* to the output buffer prior to call. If any escaping is needed,
* it will also be handled by the method.
*<p>
* Note: when called, textual content to write is within output
* buffer, right after buffered content (if any). That's why only
* length of that text is passed, as buffer and offset are implied.
*/
private void _writeSegment(int end) throws IOException
{
final int[] escCodes = _outputEscapes;
final int escLen = escCodes.length;
int ptr = 0;
int start = ptr;
output_loop:
while (ptr < end) {
// Fast loop for chars not needing escaping
char c;
while (true) {
c = _outputBuffer[ptr];
if (c < escLen && escCodes[c] != 0) {
break;
}
if (++ptr >= end) {
break;
}
}
// Ok, bumped into something that needs escaping.
/* First things first: need to flush the buffer.
* Inlined, as we don't want to lose tail pointer
*/
int flushLen = (ptr - start);
if (flushLen > 0) {
_writer.write(_outputBuffer, start, flushLen);
if (ptr >= end) {
break output_loop;
}
}
++ptr;
// So; either try to prepend (most likely), or write directly:
start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCodes[c]);
}
}
/**
* This method called when the string content is already
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> in
* a char buffer, and need not be copied for processing.
*/
private void _writeString(char[] text, int offset, int len) throws IOException
{
if (_characterEscapes != null) {
_writeStringCustom(text, offset, len);
return;
}
if (_maximumNonEscapedChar != 0) {
_writeStringASCII(text, offset, len, _maximumNonEscapedChar);
return;
}
/* Let's just find longest spans of non-escapable
* content, and for each see if it makes sense
* to copy them, or write through
*/
len += offset; // -> len marks the end from now on
final int[] escCodes = _outputEscapes;
final int escLen = escCodes.length;
while (offset < len) {
int start = offset;
while (true) {
char c = text[offset];
if (c < escLen && escCodes[c] != 0) {
break;
}
if (++offset >= len) {
break;
}
}
// Short span? Better just copy it to buffer first:
int newAmount = offset - start;
if (newAmount < SHORT_WRITE) {
// Note: let's reserve room for escaped char (up to 6 chars)
if ((_outputTail + newAmount) > _outputEnd) {
_flushBuffer();
}
if (newAmount > 0) {
System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount);
_outputTail += newAmount;
}
} else { // Nope: better just write through
_flushBuffer();
_writer.write(text, start, newAmount);
}
// Was this the end?
if (offset >= len) { // yup
break;
}
// Nope, need to escape the char.
char c = text[offset++];
_appendCharacterEscape(c, escCodes[c]);
}
}
/*
/**********************************************************
/* Internal methods, low-level writing, text segment
/* with additional escaping (ASCII or such)
/**********************************************************
*/
/* Same as "_writeString2()", except needs additional escaping
* for subset of characters
*/
private void _writeStringASCII(final int len, final int maxNonEscaped)
throws IOException, Json
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>GenerationException
{
// And then we'll need to verify need for escaping etc:
int end = _outputTail + len;
final int[] escCodes = _outputEscapes;
final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
int escCode = 0;
output_loop:
while (_outputTail < end) {
char c;
// Fast loop for chars not needing escaping
escape_loop:
while (true) {
c = _outputBuffer[_outputTail];
if (c < escLimit) {
escCode = escCodes[c];
if (escCode != 0) {
break escape_loop;
}
} else if (c > maxNonEscaped) {
escCode = CharacterEscapes.ESCAPE_STANDARD;
break escape_loop;
}
if (++_outputTail >= end) {
break output_loop;
}
}
int flushLen = (_outputTail - _outputHead);
if (flushLen > 0) {
_writer.write(_outputBuffer, _outputHead, flushLen);
}
++_outputTail;
_prependOrWriteCharacterEscape(c, escCode);
}
}
private void _writeSegmentASCII(int end, final int maxNonEscaped)
throws IOException, JsonGenerationException
{
final int[] escCodes = _outputEscapes;
final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
int ptr = 0;
int escCode = 0;
int start = ptr;
output_loop:
while (ptr < end) {
// Fast loop for chars not needing escaping
char c;
while (true) {
c = _outputBuffer[ptr];
if (c < escLimit) {
escCode = escCodes[c];
if (escCode != 0) {
break;
}
} else if (c > maxNonEscaped) {
escCode = CharacterEscapes.ESCAPE_STANDARD;
break;
}
if (++ptr >= end) {
break;
}
}
int flushLen = (ptr - start);
if (flushLen > 0) {
_writer.write(_outputBuffer, start, flushLen);
if (ptr >= end) {
break output_loop;
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> }
}
++ptr;
start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCode);
}
}
private void _writeStringASCII(char[] text, int offset, int len,
final int maxNonEscaped)
throws IOException, JsonGenerationException
{
len += offset; // -> len marks the end from now on
final int[] escCodes = _outputEscapes;
final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
int escCode = 0;
while (offset < len) {
int start = offset;
char c;
while (true) {
c = text[offset];
if (c < escLimit) {
escCode = escCodes[c];
if (escCode != 0) {
break;
}
} else if (c > maxNonEscaped) {
escCode = CharacterEscapes.ESCAPE_STANDARD;
break;
}
if (++offset >= len) {
break;
}
}
// Short span? Better just copy it to buffer first:
int newAmount = offset - start;
if (newAmount < SHORT_WRITE) {
// Note: let's reserve room for escaped char (up to 6 chars)
if ((_outputTail + newAmount) > _outputEnd) {
_flushBuffer();
}
if (newAmount > 0) {
System.arraycopy(text, start, _outputBuffer, _outputTail, newAmount);
_outputTail += newAmount;
}
} else { // Nope: better just write through
_flushBuffer();
_writer.write(text, start, newAmount);
}
// Was this the end?
if (offset >= len) { // yup
break;
}
// Nope, need to escape the char.
++offset;
_appendCharacterEscape(c, escCode);
}
}
/*
/**********************************************************
/* Internal methods, low-level writing, text segment
/* with custom escaping (possibly coupling with ASCII limits)
/**********************************************************
*/
/* Same as "_writeString2()", except needs additional escaping
* for subset of characters
*/
private void _writeStringCustom(final int len)
throws IOException, JsonGenerationException
{
// And then we'll need to verify need for escaping etc
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>:
int end = _outputTail + len;
final int[] escCodes = _outputEscapes;
final int maxNonEscaped = (_maximumNonEscapedChar < 1) ? 0xFFFF : _maximumNonEscapedChar;
final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
int escCode = 0;
final CharacterEscapes customEscapes = _characterEscapes;
output_loop:
while (_outputTail < end) {
char c;
// Fast loop for chars not needing escaping
escape_loop:
while (true) {
c = _outputBuffer[_outputTail];
if (c < escLimit) {
escCode = escCodes[c];
if (escCode != 0) {
break escape_loop;
}
} else if (c > maxNonEscaped) {
escCode = CharacterEscapes.ESCAPE_STANDARD;
break escape_loop;
} else {
if ((_currentEscape = customEscapes.getEscapeSequence(c)) != null) {
escCode = CharacterEscapes.ESCAPE_CUSTOM;
break escape_loop;
}
}
if (++_outputTail >= end) {
break output_loop;
}
}
int flushLen = (_outputTail - _outputHead);
if (flushLen > 0) {
_writer.write(_outputBuffer, _outputHead, flushLen);
}
++_outputTail;
_prependOrWriteCharacterEscape(c, escCode);
}
}
private void _writeSegmentCustom(int end)
throws IOException, JsonGenerationException
{
final int[] escCodes = _outputEscapes;
final int maxNonEscaped = (_maximumNonEscapedChar < 1) ? 0xFFFF : _maximumNonEscapedChar;
final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
final CharacterEscapes customEscapes = _characterEscapes;
int ptr = 0;
int escCode = 0;
int start = ptr;
output_loop:
while (ptr < end) {
// Fast loop for chars not needing escaping
char c;
while (true) {
c = _outputBuffer[ptr];
if (c < escLimit) {
escCode = escCodes[c];
if
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> (escCode != 0) {
break;
}
} else if (c > maxNonEscaped) {
escCode = CharacterEscapes.ESCAPE_STANDARD;
break;
} else {
if ((_currentEscape = customEscapes.getEscapeSequence(c)) != null) {
escCode = CharacterEscapes.ESCAPE_CUSTOM;
break;
}
}
if (++ptr >= end) {
break;
}
}
int flushLen = (ptr - start);
if (flushLen > 0) {
_writer.write(_outputBuffer, start, flushLen);
if (ptr >= end) {
break output_loop;
}
}
++ptr;
start = _prependOrWriteCharacterEscape(_outputBuffer, ptr, end, c, escCode);
}
}
private void _writeStringCustom(char[] text, int offset, int len)
throws IOException, JsonGenerationException
{
len += offset; // -> len marks the end from now on
final int[] escCodes = _outputEscapes;
final int maxNonEscaped = (_maximumNonEscapedChar < 1) ? 0xFFFF : _maximumNonEscapedChar;
final int escLimit = Math.min(escCodes.length, maxNonEscaped+1);
final CharacterEscapes customEscapes = _characterEscapes;
int escCode = 0;
while (offset < len) {
int start = offset;
char c;
while (true) {
c = text[offset];
if (c < escLimit) {
escCode = escCodes[c];
if (escCode != 0) {
break;
}
} else if (c > maxNonEscaped) {
escCode = CharacterEscapes.ESCAPE_STANDARD;
break;
} else {
if ((_currentEscape = customEscapes.getEscapeSequence(c)) != null) {
escCode = CharacterEscapes.ESCAPE_CUSTOM;
break;
}
}
if (++offset >= len) {
break;
}
}
// Short span? Better just copy it to buffer first:
int newAmount = offset - start;
if (newAmount < SHORT_WRITE) {
// Note: let's reserve room for escaped char (up to 6 chars)
if ((_outputTail + newAmount) > _outputEnd) {
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>outputTail++] = 'n';
chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
}
}
// And then we may have 1 or 2 leftover bytes to encode
if (bytesLeft > 0) {
inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, bytesLeft);
inputPtr = 0;
if (inputEnd > 0) { // yes, but do we have room for output?
if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
_flushBuffer();
}
int b24 = ((int) readBuffer[inputPtr++]) << 16;
int amount;
if (inputPtr < inputEnd) {
b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
amount = 2;
} else {
amount = 1;
}
_outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
bytesLeft -= amount;
}
}
return bytesLeft;
}
// write method when length is unknown
protected int _writeBinary(Base64Variant b64variant,
InputStream data, byte[] readBuffer)
throws IOException, JsonGenerationException
{
int inputPtr = 0;
int inputEnd = 0;
int lastFullOffset = -3;
int bytesDone = 0;
// Let's also reserve room for possible (and quoted) LF char each round
int safeOutputEnd = _outputEnd - 6;
int chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
// Ok, first we loop through all full triplets of data:
while (true) {
if (inputPtr > lastFullOffset) { // need to load more
inputEnd = _readMore(data, readBuffer, inputPtr, inputEnd, readBuffer.length);
inputPtr = 0;
if (inputEnd < 3) { // required to try to read to have at least 3 bytes
break;
}
lastFullOffset = inputEnd-3;
}
if (_outputTail > safeOutputEnd) { // need to flush
_flushBuffer();
}
// First, mash 3 bytes into l
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>sb of 32-bit int
int b24 = ((int) readBuffer[inputPtr++]) << 8;
b24 |= ((int) readBuffer[inputPtr++]) & 0xFF;
b24 = (b24 << 8) | (((int) readBuffer[inputPtr++]) & 0xFF);
bytesDone += 3;
_outputTail = b64variant.encodeBase64Chunk(b24, _outputBuffer, _outputTail);
if (--chunksBeforeLF <= 0) {
_outputBuffer[_outputTail++] = '\\';
_outputBuffer[_outputTail++] = 'n';
chunksBeforeLF = b64variant.getMaxLineLength() >> 2;
}
}
// And then we may have 1 or 2 leftover bytes to encode
if (inputPtr < inputEnd) { // yes, but do we have room for output?
if (_outputTail > safeOutputEnd) { // don't really need 6 bytes but...
_flushBuffer();
}
int b24 = ((int) readBuffer[inputPtr++]) << 16;
int amount = 1;
if (inputPtr < inputEnd) {
b24 |= (((int) readBuffer[inputPtr]) & 0xFF) << 8;
amount = 2;
}
bytesDone += amount;
_outputTail = b64variant.encodeBase64Partial(b24, amount, _outputBuffer, _outputTail);
}
return bytesDone;
}
private int _readMore(InputStream in,
byte[] readBuffer, int inputPtr, int inputEnd,
int maxRead) throws IOException
{
// anything to shift to front?
int i = 0;
while (inputPtr < inputEnd) {
readBuffer[i++] = readBuffer[inputPtr++];
}
inputPtr = 0;
inputEnd = i;
maxRead = Math.min(maxRead, readBuffer.length);
do {
int length = maxRead - inputEnd;
if (length == 0) {
break;
}
int count = in.read(readBuffer, inputEnd, length);
if (count < 0) {
return inputEnd;
}
inputEnd += count;
} while (inputEnd <
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> >> 4];
buf[++ptr] = HEX_CHARS[hi & 0xF];
ch &= 0xFF;
} else {
buf[++ptr] = '0';
buf[++ptr] = '0';
}
buf[++ptr] = HEX_CHARS[ch >> 4];
buf[++ptr] = HEX_CHARS[ch & 0xF];
return;
}
// won't fit, flush and write
char[] buf = _entityBuffer;
if (buf == null) {
buf = _allocateEntityBuffer();
}
_outputHead = _outputTail;
if (ch > 0xFF) { // beyond 8 bytes
int hi = (ch >> 8) & 0xFF;
int lo = ch & 0xFF;
buf[10] = HEX_CHARS[hi >> 4];
buf[11] = HEX_CHARS[hi & 0xF];
buf[12] = HEX_CHARS[lo >> 4];
buf[13] = HEX_CHARS[lo & 0xF];
_writer.write(buf, 8, 6);
} else { // We know it's a control char, so only the last 2 chars are non-0
buf[6] = HEX_CHARS[ch >> 4];
buf[7] = HEX_CHARS[ch & 0xF];
_writer.write(buf, 2, 6);
}
return;
}
String escape;
if (_currentEscape == null) {
escape = _characterEscapes.getEscapeSequence(ch).getValue();
} else {
escape = _currentEscape.getValue();
_currentEscape = null;
}
int len = escape.length();
if (_outputTail >= len) { // fits in, prepend
int ptr = _outputTail - len;
_outputHead = ptr;
escape.getChars(0, len, _outputBuffer, ptr);
return;
}
// won't fit, write separately
_outputHead = _outputTail;
_writer.write(escape);
}
/**
* Method called to try to either prepend character escape at front of
* given buffer; or if not possible, to write it out directly.
*
* @return Pointer to start of prepended entity (if prepended); or 'ptr'
* if
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>4];
ent[13] = HEX_CHARS[lo & 0xF];
_writer.write(ent, 8, 6);
} else { // We know it's a control char, so only the last 2 chars are non-0
ent[6] = HEX_CHARS[ch >> 4];
ent[7] = HEX_CHARS[ch & 0xF];
_writer.write(ent, 2, 6);
}
}
return ptr;
}
String escape;
if (_currentEscape == null) {
escape = _characterEscapes.getEscapeSequence(ch).getValue();
} else {
escape = _currentEscape.getValue();
_currentEscape = null;
}
int len = escape.length();
if (ptr >= len && ptr < end) { // fits in, prepend
ptr -= len;
escape.getChars(0, len, buffer, ptr);
} else { // won't fit, write separately
_writer.write(escape);
}
return ptr;
}
/**
* Method called to append escape sequence for given character, at the
* end of standard output buffer; or if not possible, write out directly.
*/
private void _appendCharacterEscape(char ch, int escCode)
throws IOException, JsonGenerationException
{
if (escCode >= 0) { // \\N (2 char)
if ((_outputTail + 2) > _outputEnd) {
_flushBuffer();
}
_outputBuffer[_outputTail++] = '\\';
_outputBuffer[_outputTail++] = (char) escCode;
return;
}
if (escCode != CharacterEscapes.ESCAPE_CUSTOM) { // std, \\uXXXX
if ((_outputTail + 5) >= _outputEnd) {
_flushBuffer();
}
int ptr = _outputTail;
char[] buf = _outputBuffer;
buf[ptr++] = '\\';
buf[ptr++] = 'u';
// We know it's a control char, so only the last 2 chars are non-0
if (ch > 0xFF) { // beyond 8 bytes
int hi = (ch >> 8) & 0xFF;
buf[ptr++] = HEX_CHARS[hi >> 4];
buf[ptr++] = HEX_CHARS[hi & 0xF];
ch
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> &= 0xFF;
} else {
buf[ptr++] = '0';
buf[ptr++] = '0';
}
buf[ptr++] = HEX_CHARS[ch >> 4];
buf[ptr++] = HEX_CHARS[ch & 0xF];
_outputTail = ptr;
return;
}
String escape;
if (_currentEscape == null) {
escape = _characterEscapes.getEscapeSequence(ch).getValue();
} else {
escape = _currentEscape.getValue();
_currentEscape = null;
}
int len = escape.length();
if ((_outputTail + len) > _outputEnd) {
_flushBuffer();
if (len > _outputEnd) { // very very long escape; unlikely but theoretically possible
_writer.write(escape);
return;
}
}
escape.getChars(0, len, _outputBuffer, _outputTail);
_outputTail += len;
}
private char[] _allocateEntityBuffer()
{
char[] buf = new char[14];
// first 2 chars, non-numeric escapes (like \n)
buf[0] = '\\';
// next 6; 8-bit escapes (control chars mostly)
buf[2] = '\\';
buf[3] = 'u';
buf[4] = '0';
buf[5] = '0';
// last 6, beyond 8 bits
buf[8] = '\\';
buf[9] = 'u';
_entityBuffer = buf;
return buf;
}
protected void _flushBuffer() throws IOException
{
int len = _outputTail - _outputHead;
if (len > 0) {
int offset = _outputHead;
_outputTail = _outputHead = 0;
_writer.write(_outputBuffer, offset, len);
}
}
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>_BUFFER, buf);
}
}
public void releaseBase64Buffer(byte[] buf) {
if (buf != null) { // sanity checks, release once-and-only-once, must be one owned
_verifyRelease(buf, _base64Buffer);
_base64Buffer = null;
_bufferRecycler.releaseByteBuffer(BufferRecycler.BYTE_BASE64_CODEC_BUFFER, buf);
}
}
public void releaseTokenBuffer(char[] buf) {
if (buf != null) {
_verifyRelease(buf, _tokenCBuffer);
_tokenCBuffer = null;
_bufferRecycler.releaseCharBuffer(BufferRecycler.CHAR_TOKEN_BUFFER, buf);
}
}
public void releaseConcatBuffer(char[] buf) {
if (buf != null) {
// 14-Jan-2014, tatu: Let's actually allow upgrade of the original buffer.
_verifyRelease(buf, _concatCBuffer);
_concatCBuffer = null;
_bufferRecycler.releaseCharBuffer(BufferRecycler.CHAR_CONCAT_BUFFER, buf);
}
}
public void releaseNameCopyBuffer(char[] buf) {
if (buf != null) {
// 14-Jan-2014, tatu: Let's actually allow upgrade of the original buffer.
_verifyRelease(buf, _nameCopyBuffer);
_nameCopyBuffer = null;
_bufferRecycler.releaseCharBuffer(BufferRecycler.CHAR_NAME_COPY_BUFFER, buf);
}
}
/*
/**********************************************************
/* Internal helpers
/**********************************************************
*/
protected final void _verifyAlloc(Object buffer) {
if (buffer != null) { throw new IllegalStateException("Trying to call same allocXxx() method second time"); }
}
protected final void _verifyRelease(byte[] toRelease, byte[] src) {
if ((toRelease != src) && (toRelease.length <= src.length)) { throw wrongBuf(); }
}
protected final void _verifyRelease(char[] toRelease, char[] src) {
if ((toRelease != src) && (toRelease.length <= src.length)) { throw wrongBuf(); }
}
private IllegalArgumentException wrongBuf() { return new IllegalArgumentException("Trying to release buffer not owned by the context"); }
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>(_tmpBuf, 0, 1) < 1) {
return -1;
}
return _tmpBuf[0];
}
@Override
public int read(char[] cbuf, int start, int len) throws IOException {
// Already EOF?
if (_buffer == null) { return -1; }
if (len < 1) { return len; }
// Let's then ensure there's enough room...
if (start < 0 || (start+len) > cbuf.length) {
reportBounds(cbuf, start, len);
}
len += start;
int outPtr = start;
// Ok, first; do we have a surrogate from last round?
if (_surrogate != NC) {
cbuf[outPtr++] = _surrogate;
_surrogate = NC;
// No need to load more, already got one char
} else {
/* Note: we'll try to avoid blocking as much as possible. As a
* result, we only need to get 4 bytes for a full char.
*/
int left = (_length - _ptr);
if (left < 4) {
if (!loadMore(left)) { // (legal) EOF?
return -1;
}
}
}
main_loop:
while (outPtr < len) {
int ptr = _ptr;
int ch;
if (_bigEndian) {
ch = (_buffer[ptr] << 24) | ((_buffer[ptr+1] & 0xFF) << 16)
| ((_buffer[ptr+2] & 0xFF) << 8) | (_buffer[ptr+3] & 0xFF);
} else {
ch = (_buffer[ptr] & 0xFF) | ((_buffer[ptr+1] & 0xFF) << 8)
| ((_buffer[ptr+2] & 0xFF) << 16) | (_buffer[ptr+3] << 24);
}
_ptr += 4;
// Does it need to be split to surrogates?
// (also, we can and need to verify illegal chars)
if (ch > 0xFFFF) { // need to split into surrogates?
if (ch > LAST_VALID_UNICODE_CHAR) {
reportInvalid(ch, outPtr-start,
"(
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
/* Ok; here we can actually reasonably expect an EOF,
* so let's do a separate read right away:
*/
_ptr = 0;
int count = (_in == null) ? -1 : _in.read(_buffer);
if (count < 1) {
_length = 0;
if (count < 0) { // -1
if (_managedBuffers) {
freeBuffers(); // to help GC?
}
return false;
}
// 0 count is no good; let's err out
reportStrangeStream();
}
_length = count;
}
/* Need at least 4 bytes; if we don't get that many, it's an
* error.
*/
while (_length < 4) {
int count = (_in == null) ? -1 : _in.read(_buffer, _length, _buffer.length - _length);
if (count < 1) {
if (count < 0) { // -1, EOF... no good!
if (_managedBuffers) {
freeBuffers(); // to help GC?
}
reportUnexpectedEOF(_length, 4);
}
// 0 count is no good; let's err out
reportStrangeStream();
}
_length += count;
}
return true;
}
/**
* This method should be called along with (or instead of) normal
* close. After calling this method, no further reads should be tried.
* Method will try to recycle read buffers (if any).
*/
private void freeBuffers() {
byte[] buf = _buffer;
if (buf != null) {
_buffer = null;
_context.releaseReadIOBuffer(buf);
}
}
private void reportBounds(char[] cbuf, int start, int len) throws IOException {
throw new ArrayIndexOutOfBoundsException("read(buf,"+start+","+len+"), cbuf["+cbuf.length+"]");
}
private void reportStrangeStream() throws IOException {
throw new IOException("Strange I/O stream, returned 0 bytes on read");
}
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
*/
/**
* Ugly hack, to work through the requirement that _value is indeed final,
* and that JDK serialization won't call ctor(s).
*
* @since 2.1
*/
protected transient String _jdkSerializeValue;
private void readObject(ObjectInputStream in) throws IOException {
_jdkSerializeValue = in.readUTF();
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeUTF(_value);
}
protected Object readResolve() {
return new SerializedString(_jdkSerializeValue);
}
/*
/**********************************************************
/* API
/**********************************************************
*/
@Override
public final String getValue() { return _value; }
/**
* Returns length of the String as characters
*/
@Override
public final int charLength() { return _value.length(); }
@Override
public final char[] asQuotedChars() {
char[] result = _quotedChars;
if (result == null) {
result = JsonStringEncoder.getInstance().quoteAsString(_value);
_quotedChars = result;
}
return result;
}
/**
* Accessor for accessing value that has been quoted using JSON
* quoting rules, and encoded using UTF-8 encoding.
*/
@Override
public final byte[] asUnquotedUTF8() {
byte[] result = _unquotedUTF8Ref;
if (result == null) {
result = JsonStringEncoder.getInstance().encodeAsUTF8(_value);
_unquotedUTF8Ref = result;
}
return result;
}
/**
* Accessor for accessing value as is (without JSON quoting)
* encoded using UTF-8 encoding.
*/
@Override
public final byte[] asQuotedUTF8() {
byte[] result = _quotedUTF8Ref;
if (result == null) {
result = JsonStringEncoder.getInstance().quoteAsUTF8(_value);
_quotedUTF8Ref = result;
}
return result;
}
/*
/**********************************************************
/* Additional 2.0 methods for appending/writing contents
/**********************************************************
*/
@Override
public int appendQuotedUTF8(byte[] buffer, int offset) {
byte[] result = _quotedUTF8Ref;
if (result == null) {
result = JsonStringEncoder.getInstance().quoteAsUTF8(_value);
_quotedUTF8
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>Ref = result;
}
final int length = result.length;
if ((offset + length) > buffer.length) {
return -1;
}
System.arraycopy(result, 0, buffer, offset, length);
return length;
}
@Override
public int appendQuoted(char[] buffer, int offset) {
char[] result = _quotedChars;
if (result == null) {
result = JsonStringEncoder.getInstance().quoteAsString(_value);
_quotedChars = result;
}
final int length = result.length;
if ((offset + length) > buffer.length) {
return -1;
}
System.arraycopy(result, 0, buffer, offset, length);
return length;
}
@Override
public int appendUnquotedUTF8(byte[] buffer, int offset) {
byte[] result = _unquotedUTF8Ref;
if (result == null) {
result = JsonStringEncoder.getInstance().encodeAsUTF8(_value);
_unquotedUTF8Ref = result;
}
final int length = result.length;
if ((offset + length) > buffer.length) {
return -1;
}
System.arraycopy(result, 0, buffer, offset, length);
return length;
}
@Override
public int appendUnquoted(char[] buffer, int offset) {
String str = _value;
final int length = str.length();
if ((offset + length) > buffer.length) {
return -1;
}
str.getChars(0, length, buffer, offset);
return length;
}
@Override
public int writeQuotedUTF8(OutputStream out) throws IOException {
byte[] result = _quotedUTF8Ref;
if (result == null) {
result = JsonStringEncoder.getInstance().quoteAsUTF8(_value);
_quotedUTF8Ref = result;
}
final int length = result.length;
out.write(result, 0, length);
return length;
}
@Override
public int writeUnquotedUTF8(OutputStream out) throws IOException {
byte[] result = _unquotedUTF8Ref;
if (result == null) {
result = JsonStringEncoder.getInstance().encodeAsUTF8(_value);
_unquotedUTF8Ref = result;
}
final int length = result.
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>length;
out.write(result, 0, length);
return length;
}
@Override
public int putQuotedUTF8(ByteBuffer buffer) {
byte[] result = _quotedUTF8Ref;
if (result == null) {
result = JsonStringEncoder.getInstance().quoteAsUTF8(_value);
_quotedUTF8Ref = result;
}
final int length = result.length;
if (length > buffer.remaining()) {
return -1;
}
buffer.put(result, 0, length);
return length;
}
@Override
public int putUnquotedUTF8(ByteBuffer buffer) {
byte[] result = _unquotedUTF8Ref;
if (result == null) {
result = JsonStringEncoder.getInstance().encodeAsUTF8(_value);
_unquotedUTF8Ref = result;
}
final int length = result.length;
if (length > buffer.remaining()) {
return -1;
}
buffer.put(result, 0, length);
return length;
}
/*
/**********************************************************
/* Standard method overrides
/**********************************************************
*/
@Override
public final String toString() { return _value; }
@Override
public final int hashCode() { return _value.hashCode(); }
@Override
public final boolean equals(Object o) {
if (o == this) return true;
if (o == null || o.getClass() != getClass()) return false;
SerializedString other = (SerializedString) o;
return _value.equals(other._value);
}
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> values()) {
if (f.enabledByDefault()) {
flags |= f.getMask();
}
}
return flags;
}
private Feature(boolean defaultState) {
_defaultState = defaultState;
_mask = (1 << ordinal());
}
public boolean enabledByDefault() { return _defaultState; }
/**
* @since 2.3
*/
public boolean enabledIn(int flags) { return (flags & _mask) != 0; }
public int getMask() { return _mask; }
}
/*
/**********************************************************
/* Configuration
/**********************************************************
*/
/**
* Object that handles pretty-printing (usually additional
* white space to make results more human-readable) during
* output. If null, no pretty-printing is done.
*/
protected PrettyPrinter _cfgPrettyPrinter;
/*
/**********************************************************
/* Construction, initialization
/**********************************************************
*/
protected JsonGenerator() { }
/**
* Method that can be called to set or reset the object to
* use for writing Java objects as JsonContent
* (using method {@link #writeObject}).
*
* @return Generator itself (this), to allow chaining
*/
public abstract JsonGenerator setCodec(ObjectCodec oc);
/**
* Method for accessing the object used for writing Java
* object as JSON content
* (using method {@link #writeObject}).
*/
public abstract ObjectCodec getCodec();
/**
* Accessor for finding out version of the bundle that provided this generator instance.
*/
@Override
public abstract Version version();
/*
/**********************************************************
/* Forward-compatibility additions in 2.7.5: placeholders
/* for additions that will be in 2.8.0
/**********************************************************
*/
// @since 2.7.5 (as placeholder, NOT full impl)
public boolean canWriteFormattedNumbers() { return false; }
// @since 2.7.5: default impl that should work fine
public void writeStartObject(Object forValue) throws IOException
{
writeStartObject();
setCurrentValue(forValue);
}
// @since 2.7.5: default impl that should work fine
public void writeArray(int[] array, int offset, int length) throws IOException
{
writeStartArray();
for (int i = offset, end = offset+length; i < end; ++i
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>) {
writeNumber(array[i]);
}
writeEndArray();
}
// @since 2.7.5: default impl that should work fine
public void writeArray(long[] array, int offset, int length) throws IOException
{
writeStartArray();
for (int i = offset, end = offset+length; i < end; ++i) {
writeNumber(array[i]);
}
writeEndArray();
}
// @since 2.7.5: default impl that should work fine
public void writeArray(double[] array, int offset, int length) throws IOException
{
writeStartArray();
for (int i = offset, end = offset+length; i < end; ++i) {
writeNumber(array[i]);
}
writeEndArray();
}
/*
/**********************************************************
/* Public API, Feature configuration
/**********************************************************
*/
/**
* Method for enabling specified parser features:
* check {@link Feature} for list of available features.
*
* @return Generator itself (this), to allow chaining
*/
public abstract JsonGenerator enable(Feature f);
/**
* Method for disabling specified features
* (check {@link Feature} for list of features)
*
* @return Generator itself (this), to allow chaining
*/
public abstract JsonGenerator disable(Feature f);
/**
* Method for enabling or disabling specified feature:
* check {@link Feature} for list of available features.
*
* @return Generator itself (this), to allow chaining
*/
public final JsonGenerator configure(Feature f, boolean state) {
if (state) enable(f); else disable(f);
return this;
}
/**
* Method for checking whether given feature is enabled.
* Check {@link Feature} for list of available features.
*/
public abstract boolean isEnabled(Feature f);
/**
* Bulk access method for getting state of all standard (non-dataformat-specific)
* {@link JsonGenerator.Feature}s.
*
* @return Bit mask that defines current states of all standard {@link JsonGenerator.Feature}s.
*
* @since 2.3
*/
public abstract int getFeatureMask();
/**
* Bulk set method for (re)setting states of all standard {@link Feature}s
*
* @since 2.3
*
* @
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>rounded in double quotes, and contents will be properly
* escaped as required by JSON specification.
*/
public abstract void writeString(String text) throws IOException;
/**
* Method for outputting a String value. Depending on context
* this means either array element, (object) field value or
* a stand alone String; but in all cases, String will be
* surrounded in double quotes, and contents will be properly
* escaped as required by JSON specification.
*/
public abstract void writeString(char[] text, int offset, int len) throws IOException;
/**
* Method similar to {@link #writeString(String)}, but that takes
* {@link SerializableString} which can make this potentially
* more efficient to call as generator may be able to reuse
* quoted and/or encoded representation.
*<p>
* Default implementation just calls {@link #writeString(String)};
* sub-classes should override it with more efficient implementation
* if possible.
*/
public abstract void writeString(SerializableString text) throws IOException;
/**
* Method similar to {@link #writeString(String)} but that takes as
* its input a UTF-8 encoded String that is to be output as-is, without additional
* escaping (type of which depends on data format; backslashes for JSON).
* However, quoting that data format requires (like double-quotes for JSON) will be added
* around the value if and as necessary.
*<p>
* Note that some backends may choose not to support this method: for
* example, if underlying destination is a {@link java.io.Writer}
* using this method would require UTF-8 decoding.
* If so, implementation may instead choose to throw a
* {@link UnsupportedOperationException} due to ineffectiveness
* of having to decode input.
*/
public abstract void writeRawUTF8String(byte[] text, int offset, int length)
throws IOException;
/**
* Method similar to {@link #writeString(String)} but that takes as its input
* a UTF-8 encoded String which has <b>not</b> been escaped using whatever
* escaping scheme data format requires (for JSON that is backslash-escaping
* for control characters and double-quotes; for other formats something else).
* This means that textual JSON backends need to check if value needs
* JSON escaping, but otherwise can just be copied as
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> is to output.
* Also, quoting that data format requires (like double-quotes for JSON) will be added
* around the value if and as necessary.
*<p>
* Note that some backends may choose not to support this method: for
* example, if underlying destination is a {@link java.io.Writer}
* using this method would require UTF-8 decoding.
* In this case
* generator implementation may instead choose to throw a
* {@link UnsupportedOperationException} due to ineffectiveness
* of having to decode input.
*/
public abstract void writeUTF8String(byte[] text, int offset, int length)
throws IOException;
/*
/**********************************************************
/* Public API, write methods, binary/raw content
/**********************************************************
*/
/**
* Method that will force generator to copy
* input text verbatim with <b>no</b> modifications (including
* that no escaping is done and no separators are added even
* if context [array, object] would otherwise require such).
* If such separators are desired, use
* {@link #writeRawValue(String)} instead.
*<p>
* Note that not all generator implementations necessarily support
* such by-pass methods: those that do not will throw
* {@link UnsupportedOperationException}.
*/
public abstract void writeRaw(String text) throws IOException;
/**
* Method that will force generator to copy
* input text verbatim with <b>no</b> modifications (including
* that no escaping is done and no separators are added even
* if context [array, object] would otherwise require such).
* If such separators are desired, use
* {@link #writeRawValue(String)} instead.
*<p>
* Note that not all generator implementations necessarily support
* such by-pass methods: those that do not will throw
* {@link UnsupportedOperationException}.
*/
public abstract void writeRaw(String text, int offset, int len) throws IOException;
/**
* Method that will force generator to copy
* input text verbatim with <b>no</b> modifications (including
* that no escaping is done and no separators are added even
* if context [array, object] would otherwise require such).
* If such separators are desired, use
* {@link #writeRawValue(String)} instead.
*<p>
* Note that not all
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> writeBinary(Base64Variants.getDefaultVariant(), data, 0, data.length);
}
/**
* Similar to {@link #writeBinary(Base64Variant,InputStream,int)},
* but assumes default to using the Jackson default Base64 variant
* (which is {@link Base64Variants#MIME_NO_LINEFEEDS}).
*
* @param data InputStream to use for reading binary data to write.
* Will not be closed after successful write operation
* @param dataLength (optional) number of bytes that will be available;
* or -1 to be indicate it is not known. Note that implementations
* need not support cases where length is not known in advance; this
* depends on underlying data format: JSON output does NOT require length,
* other formats may
*/
public int writeBinary(InputStream data, int dataLength)
throws IOException {
return writeBinary(Base64Variants.getDefaultVariant(), data, dataLength);
}
/**
* Method similar to {@link #writeBinary(Base64Variant,byte[],int,int)},
* but where input is provided through a stream, allowing for incremental
* writes without holding the whole input in memory.
*
* @param bv Base64 variant to use
* @param data InputStream to use for reading binary data to write.
* Will not be closed after successful write operation
* @param dataLength (optional) number of bytes that will be available;
* or -1 to be indicate it is not known.
* If a positive length is given, <code>data</code> MUST provide at least
* that many bytes: if not, an exception will be thrown.
* Note that implementations
* need not support cases where length is not known in advance; this
* depends on underlying data format: JSON output does NOT require length,
* other formats may.
*
* @return Number of bytes read from <code>data</code> and written as binary payload
*
* @since 2.1
*/
public abstract int writeBinary(Base64Variant bv,
InputStream data, int dataLength) throws IOException;
/*
/**********************************************************
/* Public API, write methods, other value types
/**********************************************************
*/
/**
* Method for outputting given value as JSON number.
* Can be called in any context where a
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>gender) return false;
if (!_name.equals(other._name)) return false;
byte[] otherImage = other._userImage;
if (otherImage.length != _userImage.length) return false;
for (int i = 0, len = _userImage.length; i < len; ++i) {
if (_userImage[i] != otherImage[i]) {
return false;
}
}
return true;
}
}
/*
/**********************************************************
/* High-level helpers
/**********************************************************
*/
protected void verifyJsonSpecSampleDoc(JsonParser jp, boolean verifyContents)
throws IOException
{
verifyJsonSpecSampleDoc(jp, verifyContents, true);
}
protected void verifyJsonSpecSampleDoc(JsonParser jp, boolean verifyContents,
boolean requireNumbers)
throws IOException
{
if (!jp.hasCurrentToken()) {
jp.nextToken();
}
assertToken(JsonToken.START_OBJECT, jp.getCurrentToken()); // main object
assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'Image'
if (verifyContents) {
verifyFieldName(jp, "Image");
}
assertToken(JsonToken.START_OBJECT, jp.nextToken()); // 'image' object
assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'Width'
if (verifyContents) {
verifyFieldName(jp, "Width");
}
verifyIntToken(jp.nextToken(), requireNumbers);
if (verifyContents) {
verifyIntValue(jp, SAMPLE_SPEC_VALUE_WIDTH);
}
assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'Height'
if (verifyContents) {
verifyFieldName(jp, "Height");
}
verifyIntToken(jp.nextToken(), requireNumbers);
if (verifyContents) {
verifyIntValue(jp, SAMPLE_SPEC_VALUE_HEIGHT);
}
assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'Title'
if (verifyContents) {
verifyFieldName(jp, "Title");
}
assertToken(JsonToken.VALUE_STRING, jp.nextToken());
assertEquals(SAMPLE_SPEC_VALUE_TITLE, getAndVerifyText(jp));
assertToken(JsonToken.FIELD_NAME, jp.nextToken()); // 'Thumbnail'
if (verifyContents) {
verifyFieldName
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
}
}
fail("Expected an exception with one of substrings ("+Arrays.asList(matches)+"): got one with message \""+msg+"\"");
}
/**
* Method that gets textual contents of the current token using
* available methods, and ensures results are consistent, before
* returning them
*/
protected String getAndVerifyText(JsonParser jp) throws IOException
{
// Ok, let's verify other accessors
int actLen = jp.getTextLength();
char[] ch = jp.getTextCharacters();
String str2 = new String(ch, jp.getTextOffset(), actLen);
String str = jp.getText();
if (str.length() != actLen) {
fail("Internal problem (jp.token == "+jp.getCurrentToken()+"): jp.getText().length() ['"+str+"'] == "+str.length()+"; jp.getTextLength() == "+actLen);
}
assertEquals("String access via getText(), getTextXxx() must be the same", str, str2);
return str;
}
/*
/**********************************************************
/* And other helpers
/**********************************************************
*/
protected byte[] encodeInUTF32BE(String input)
{
int len = input.length();
byte[] result = new byte[len * 4];
int ptr = 0;
for (int i = 0; i < len; ++i, ptr += 4) {
char c = input.charAt(i);
result[ptr] = result[ptr+1] = (byte) 0;
result[ptr+2] = (byte) (c >> 8);
result[ptr+3] = (byte) c;
}
return result;
}
protected String quote(String str) {
return '"'+str+'"';
}
protected String aposToQuotes(String json) {
return json.replace("'", "\"");
}
protected void fieldNameFor(StringBuilder sb, int index)
{
/* let's do something like "f1.1" to exercise different
* field names (important for byte-based codec)
* Other name shuffling done mostly just for fun... :)
*/
sb.append(FIELD_BASENAME);
sb.append(index);
if (index > 50) {
sb.append('.');
if (index > 200) {
sb.append(
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>index);
if (index > 4000) { // and some even longer symbols...
sb.append(".").append(index);
}
} else {
sb.append(index >> 3); // divide by 8
}
}
}
protected String fieldNameFor(int index)
{
StringBuilder sb = new StringBuilder(16);
fieldNameFor(sb, index);
return sb.toString();
}
protected int[] calcQuads(byte[] wordBytes) {
int blen = wordBytes.length;
int[] result = new int[(blen + 3) / 4];
for (int i = 0; i < blen; ++i) {
int x = wordBytes[i] & 0xFF;
if (++i < blen) {
x = (x << 8) | (wordBytes[i] & 0xFF);
if (++i < blen) {
x = (x << 8) | (wordBytes[i] & 0xFF);
if (++i < blen) {
x = (x << 8) | (wordBytes[i] & 0xFF);
}
}
}
result[i >> 2] = x;
}
return result;
}
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>)) { // over 50%
int spillCount = (_spilloverEnd - _spilloverStart()) >> 2;
if ((spillCount > (1 + _count >> 7))
|| (_count > (_hashSize * 0.80))) {
_needRehash = true;
}
}
}
private void _verifySharing()
{
if (_hashShared) {
_hashArea = Arrays.copyOf(_hashArea, _hashArea.length);
_names = Arrays.copyOf(_names, _names.length);
_hashShared = false;
// 09-Sep-2015, tatu: As per [jackson-core#216], also need to ensure
// we rehash as needed, as need-rehash flag is not copied from parent
_verifyNeedForRehash();
}
if (_needRehash) {
rehash();
}
}
/**
* Method called to find the location within hash table to add a new symbol in.
*/
private int _findOffsetForAdd(int hash)
{
// first, check the primary:
int offset = _calcOffset(hash);
final int[] hashArea = _hashArea;
if (hashArea[offset+3] == 0) {
//System.err.printf(" PRImary slot #%d, hash %X\n", (offset>>2), hash & 0x7F);
return offset;
}
// then secondary
int offset2 = _secondaryStart + ((offset >> 3) << 2);
if (hashArea[offset2+3] == 0) {
//System.err.printf(" SECondary slot #%d (start x%X), hash %X\n",(offset >> 3), _secondaryStart, (hash & 0x7F));
return offset2;
}
// if not, tertiary?
offset2 = _tertiaryStart + ((offset >> (_tertiaryShift + 2)) << _tertiaryShift);
final int bucketSize = (1 << _tertiaryShift);
for (int end = offset2 + bucketSize; offset2 < end; offset2 += 4) {
if (hashArea[offset2+3] == 0) {
//System.err.printf(" TERti
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>ary slot x%X (from x%X, start x%X), hash %X.\n", offset2, ((offset >> (_tertiaryShift + 2)) << _tertiaryShift), _tertiaryStart, (hash & 0x7F));
return offset2;
}
}
// and if even tertiary full, append at the end of spill area
offset = _spilloverEnd;
_spilloverEnd += 4;
//System.err.printf(" SPIll-over at x%X; start x%X; end x%X, hash %X\n", offset, _spilloverStart(), _hashArea.length, (hash & 0x7F));
// one caveat: in the unlikely event if spill-over filling up,
// check if that could be considered a DoS attack; handle appropriately
// (NOTE: approximate for now; we could verify details if that becomes necessary)
/* 31-Jul-2015, tatu: Note that spillover area does NOT end at end of array,
* since "long names" area follows. Instead, need to calculate from hash size.
*/
final int end = (_hashSize << 3);
if (_spilloverEnd >= end) {
if (_failOnDoS) {
_reportTooManyCollisions();
}
// and if we didn't fail, we'll simply force rehash for next add
// (which, in turn, may double up or nuke contents, depending on size etc)
_needRehash = true;
}
return offset;
}
private int _appendLongName(int[] quads, int qlen)
{
int start = _longNameOffset;
// note: at this point we must already be shared. But may not have enough space
if ((start + qlen) > _hashArea.length) {
// try to increment in reasonable chunks; at least space that we need
int toAdd = (start + qlen) - _hashArea.length;
// but at least 1/8 of regular hash area size or 16kB (whichever smaller)
int minAdd = Math.min(4096, _hashSize);
int newSize = _hashArea.length + Math.max(toAdd, minAdd
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>double up), we know there'll be no collisions during this phase.
final int[] oldHashArea = _hashArea;
final String[] oldNames = _names;
final int oldSize = _hashSize;
final int oldCount = _count;
final int newSize = oldSize + oldSize;
final int oldEnd = _spilloverEnd;
/* 13-Mar-2010, tatu: Let's guard against OOME that could be caused by
* large documents with unique (or mostly so) names
*/
if (newSize > MAX_T_SIZE) {
nukeSymbols(true);
return;
}
// double up main hash area, but do not expand long-name area:
_hashArea = new int[oldHashArea.length + (oldSize<<3)];
_hashSize = newSize;
_secondaryStart = (newSize << 2); // 4 ints per entry
_tertiaryStart = _secondaryStart + (_secondaryStart >> 1); // right after secondary
_tertiaryShift = _calcTertiaryShift(newSize);
// and simply double up name array
_names = new String[oldNames.length << 1];
nukeSymbols(false);
// Plus we can scan only through the primary hash area, looking for non-empty
// slots, without worrying about ordering. This should never reduce priority
// of existing entries: primaries remain primaries; however, due to increased
// space, secondaries may become primaries etc
int copyCount = 0;
int[] q = new int[16];
for (int offset = 0, end = oldEnd; offset < end; offset += 4) {
int len = oldHashArea[offset+3];
if (len == 0) { // empty slot, skip
continue;
}
++copyCount;
String name = oldNames[offset>>2];
switch (len) {
case 1:
q[0] = oldHashArea[offset];
addName(name, q, 1);
break;
case 2:
q[0] = oldHashArea[offset];
q[1] = oldHashArea[offset+1];
addName(name, q, 2);
break;
case 3:
q[0] =
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> oldHashArea[offset];
q[1] = oldHashArea[offset+1];
q[2] = oldHashArea[offset+2];
addName(name, q, 3);
break;
default:
if (len > q.length) {
q = new int[len];
}
// #0 is hash, #1 offset
int qoff = oldHashArea[offset+1];
System.arraycopy(oldHashArea, qoff, q, 0, len);
addName(name, q, len);
break;
}
}
// Sanity checks: since corruption difficult to detect, assert explicitly
// with production code
if (copyCount != oldCount) {
throw new IllegalStateException("Failed rehash(): old count="+oldCount+", copyCount="+copyCount);
}
}
/**
* Helper method called to empty all shared symbols, but to leave
* arrays allocated
*/
private void nukeSymbols(boolean fill) {
_count = 0;
// reset spill-over to empty (starting at 7/8 of hash area)
_spilloverEnd = _spilloverStart();
// and long name area to empty, starting immediately after hash area
_longNameOffset = _hashSize << 3;
if (fill) {
Arrays.fill(_hashArea, 0);
Arrays.fill(_names, null);
}
}
/*
/**********************************************************
/* Helper methods
/**********************************************************
*/
/**
* Helper method that calculates start of the spillover area
*/
private final int _spilloverStart() {
// we'll need slot at 1.75x of hashSize, but with 4-ints per slot.
// So basically multiply by 7
int offset = _hashSize;
return (offset << 3) - offset;
}
protected void _reportTooManyCollisions()
{
// First: do not fuzz about small symbol tables; may get balanced by doubling up
if (_hashSize <= 1024) { // would have spill-over area of 128 entries
return;
}
throw new IllegalStateException("Spill-over slots in symbol table with "+_count
+" entries, hash area of "+_hashSize+" slots is now full (all "
+(_hashSize >> 3)+"
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>_currentSegment = _segments.get(_segments.size() - 1);
_segments.clear();
_currentSize = _segmentSize = 0;
}
/*
/**********************************************************
/* Accessors for implementing public interface
/**********************************************************
*/
/**
* @return Number of characters currently stored by this collector
*/
public int size() {
if (_inputStart >= 0) { // shared copy from input buf
return _inputLen;
}
if (_resultArray != null) {
return _resultArray.length;
}
if (_resultString != null) {
return _resultString.length();
}
// local segmented buffers
return _segmentSize + _currentSize;
}
public int getTextOffset() {
/* Only shared input buffer can have non-zero offset; buffer
* segments start at 0, and if we have to create a combo buffer,
* that too will start from beginning of the buffer
*/
return (_inputStart >= 0) ? _inputStart : 0;
}
/**
* Method that can be used to check whether textual contents can
* be efficiently accessed using {@link #getTextBuffer}.
*/
public boolean hasTextAsCharacters()
{
// if we have array in some form, sure
if (_inputStart >= 0 || _resultArray != null) return true;
// not if we have String as value
if (_resultString != null) return false;
return true;
}
/**
* Accessor that may be used to get the contents of this buffer in a single
* <code>char</code> array regardless of whether they were collected in a segmented
* fashion or not.
*/
public char[] getTextBuffer()
{
// Are we just using shared input buffer?
if (_inputStart >= 0) return _inputBuffer;
if (_resultArray != null) return _resultArray;
if (_resultString != null) {
return (_resultArray = _resultString.toCharArray());
}
// Nope; but does it fit in just one segment?
if (!_hasSegments) {
return (_currentSegment == null) ? NO_CHARS : _currentSegment;
}
// Nope, need to have/create a non-segmented array and return it
return contentsAsArray();
}
/*
/**********************************************************
/* Other accessors:
/
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>**********************************************************
*/
public String contentsAsString()
{
if (_resultString == null) {
// Has array been requested? Can make a shortcut, if so:
if (_resultArray != null) {
_resultString = new String(_resultArray);
} else {
// Do we use shared array?
if (_inputStart >= 0) {
if (_inputLen < 1) {
return (_resultString = "");
}
_resultString = new String(_inputBuffer, _inputStart, _inputLen);
} else { // nope... need to copy
// But first, let's see if we have just one buffer
int segLen = _segmentSize;
int currLen = _currentSize;
if (segLen == 0) { // yup
_resultString = (currLen == 0) ? "" : new String(_currentSegment, 0, currLen);
} else { // no, need to combine
StringBuilder sb = new StringBuilder(segLen + currLen);
// First stored segments
if (_segments != null) {
for (int i = 0, len = _segments.size(); i < len; ++i) {
char[] curr = _segments.get(i);
sb.append(curr, 0, curr.length);
}
}
// And finally, current segment:
sb.append(_currentSegment, 0, _currentSize);
_resultString = sb.toString();
}
}
}
}
return _resultString;
}
public char[] contentsAsArray() {
char[] result = _resultArray;
if (result == null) {
_resultArray = result = resultArray();
}
return result;
}
/**
* Convenience method for converting contents of the buffer
* into a {@link BigDecimal}.
*/
public BigDecimal contentsAsDecimal() throws NumberFormatException
{
// Already got a pre-cut array?
if (_resultArray != null) {
return NumberInput.parseBigDecimal(_resultArray);
}
// Or a shared buffer?
if ((_inputStart >= 0) && (_inputBuffer != null)) {
return NumberInput.parseBigDecimal(_inputBuffer, _inputStart, _inputLen);
}
// Or if not, just a single buffer (the usual case)
if ((_segmentSize == 0) && (_currentSegment != null)) {
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
return NumberInput.parseBigDecimal(_currentSegment, 0, _currentSize);
}
// If not, let's just get it aggregated...
return NumberInput.parseBigDecimal(contentsAsArray());
}
/**
* Convenience method for converting contents of the buffer
* into a Double value.
*/
public double contentsAsDouble() throws NumberFormatException {
return NumberInput.parseDouble(contentsAsString());
}
/*
/**********************************************************
/* Public mutators:
/**********************************************************
*/
/**
* Method called to make sure that buffer is not using shared input
* buffer; if it is, it will copy such contents to private buffer.
*/
public void ensureNotShared() {
if (_inputStart >= 0) {
unshare(16);
}
}
public void append(char c) {
// Using shared buffer so far?
if (_inputStart >= 0) {
unshare(16);
}
_resultString = null;
_resultArray = null;
// Room in current segment?
char[] curr = _currentSegment;
if (_currentSize >= curr.length) {
expand(1);
curr = _currentSegment;
}
curr[_currentSize++] = c;
}
public void append(char[] c, int start, int len)
{
// Can't append to shared buf (sanity check)
if (_inputStart >= 0) {
unshare(len);
}
_resultString = null;
_resultArray = null;
// Room in current segment?
char[] curr = _currentSegment;
int max = curr.length - _currentSize;
if (max >= len) {
System.arraycopy(c, start, curr, _currentSize, len);
_currentSize += len;
return;
}
// No room for all, need to copy part(s):
if (max > 0) {
System.arraycopy(c, start, curr, _currentSize, max);
start += max;
len -= max;
}
/* And then allocate new segment; we are guaranteed to now
* have enough room in segment.
*/
// Except, as per [Issue-24], not for HUGE appends... so:
do {
expand(len);
int amount = Math.min(_currentSegment.length, len);
System.
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>arraycopy(c, start, _currentSegment, 0, amount);
_currentSize += amount;
start += amount;
len -= amount;
} while (len > 0);
}
public void append(String str, int offset, int len)
{
// Can't append to shared buf (sanity check)
if (_inputStart >= 0) {
unshare(len);
}
_resultString = null;
_resultArray = null;
// Room in current segment?
char[] curr = _currentSegment;
int max = curr.length - _currentSize;
if (max >= len) {
str.getChars(offset, offset+len, curr, _currentSize);
_currentSize += len;
return;
}
// No room for all, need to copy part(s):
if (max > 0) {
str.getChars(offset, offset+max, curr, _currentSize);
len -= max;
offset += max;
}
/* And then allocate new segment; we are guaranteed to now
* have enough room in segment.
*/
// Except, as per [Issue-24], not for HUGE appends... so:
do {
expand(len);
int amount = Math.min(_currentSegment.length, len);
str.getChars(offset, offset+amount, _currentSegment, 0);
_currentSize += amount;
offset += amount;
len -= amount;
} while (len > 0);
}
/*
/**********************************************************
/* Raw access, for high-performance use:
/**********************************************************
*/
public char[] getCurrentSegment()
{
/* Since the intention of the caller is to directly add stuff into
* buffers, we should NOT have anything in shared buffer... ie. may
* need to unshare contents.
*/
if (_inputStart >= 0) {
unshare(1);
} else {
char[] curr = _currentSegment;
if (curr == null) {
_currentSegment = buf(0);
} else if (_currentSize >= curr.length) {
// Plus, we better have room for at least one more char
expand(1);
}
}
return _currentSegment;
}
public char[] emptyAndGetCurrentSegment()
{
// inlined 'resetWithEmpty()'
_inputStart
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> = -1; // indicates shared buffer not used
_currentSize = 0;
_inputLen = 0;
_inputBuffer = null;
_resultString = null;
_resultArray = null;
// And then reset internal input buffers, if necessary:
if (_hasSegments) {
clearSegments();
}
char[] curr = _currentSegment;
if (curr == null) {
_currentSegment = curr = buf(0);
}
return curr;
}
public int getCurrentSegmentSize() { return _currentSize; }
public void setCurrentLength(int len) { _currentSize = len; }
/**
* @since 2.6
*/
public String setCurrentAndReturn(int len) {
_currentSize = len;
// We can simplify handling here compared to full `contentsAsString()`:
if (_segmentSize > 0) { // longer text; call main method
return contentsAsString();
}
// more common case: single segment
int currLen = _currentSize;
String str = (currLen == 0) ? "" : new String(_currentSegment, 0, currLen);
_resultString = str;
return str;
}
public char[] finishCurrentSegment() {
if (_segments == null) {
_segments = new ArrayList<char[]>();
}
_hasSegments = true;
_segments.add(_currentSegment);
int oldLen = _currentSegment.length;
_segmentSize += oldLen;
_currentSize = 0;
// Let's grow segments by 50%
int newLen = oldLen + (oldLen >> 1);
if (newLen < MIN_SEGMENT_LEN) {
newLen = MIN_SEGMENT_LEN;
} else if (newLen > MAX_SEGMENT_LEN) {
newLen = MAX_SEGMENT_LEN;
}
char[] curr = carr(newLen);
_currentSegment = curr;
return curr;
}
/**
* Method called to expand size of the current segment, to
* accommodate for more contiguous content. Usually only
* used when parsing tokens like names if even then.
*/
public char[] expandCurrentSegment()
{
final char[] curr = _currentSegment;
// Let's grow by 50% by default
final int len = curr.length;
int newLen = len
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> + (len >> 1);
// but above intended maximum, slow to increase by 25%
if (newLen > MAX_SEGMENT_LEN) {
newLen = len + (len >> 2);
}
return (_currentSegment = Arrays.copyOf(curr, newLen));
}
/**
* Method called to expand size of the current segment, to
* accommodate for more contiguous content. Usually only
* used when parsing tokens like names if even then.
*
* @param minSize Required minimum strength of the current segment
*
* @since 2.4.0
*/
public char[] expandCurrentSegment(int minSize) {
char[] curr = _currentSegment;
if (curr.length >= minSize) return curr;
_currentSegment = curr = Arrays.copyOf(curr, minSize);
return curr;
}
/*
/**********************************************************
/* Standard methods:
/**********************************************************
*/
/**
* Note: calling this method may not be as efficient as calling
* {@link #contentsAsString}, since it's not guaranteed that resulting
* String is cached.
*/
@Override public String toString() { return contentsAsString(); }
/*
/**********************************************************
/* Internal methods:
/**********************************************************
*/
/**
* Method called if/when we need to append content when we have been
* initialized to use shared buffer.
*/
private void unshare(int needExtra)
{
int sharedLen = _inputLen;
_inputLen = 0;
char[] inputBuf = _inputBuffer;
_inputBuffer = null;
int start = _inputStart;
_inputStart = -1;
// Is buffer big enough, or do we need to reallocate?
int needed = sharedLen+needExtra;
if (_currentSegment == null || needed > _currentSegment.length) {
_currentSegment = buf(needed);
}
if (sharedLen > 0) {
System.arraycopy(inputBuf, start, _currentSegment, 0, sharedLen);
}
_segmentSize = 0;
_currentSize = sharedLen;
}
/**
* Method called when current segment is full, to allocate new
* segment.
*/
private void expand(int minNewSegmentSize)
{
// First, let's move current segment to segment list:
if (_segments == null)
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> {
_segments = new ArrayList<char[]>();
}
char[] curr = _currentSegment;
_hasSegments = true;
_segments.add(curr);
_segmentSize += curr.length;
_currentSize = 0;
int oldLen = curr.length;
// Let's grow segments by 50% minimum
int newLen = oldLen + (oldLen >> 1);
if (newLen < MIN_SEGMENT_LEN) {
newLen = MIN_SEGMENT_LEN;
} else if (newLen > MAX_SEGMENT_LEN) {
newLen = MAX_SEGMENT_LEN;
}
_currentSegment = carr(newLen);
}
private char[] resultArray()
{
if (_resultString != null) { // Can take a shortcut...
return _resultString.toCharArray();
}
// Do we use shared array?
if (_inputStart >= 0) {
final int len = _inputLen;
if (len < 1) {
return NO_CHARS;
}
final int start = _inputStart;
if (start == 0) {
return Arrays.copyOf(_inputBuffer, len);
}
return Arrays.copyOfRange(_inputBuffer, start, start+len);
}
// nope, not shared
int size = size();
if (size < 1) {
return NO_CHARS;
}
int offset = 0;
final char[] result = carr(size);
if (_segments != null) {
for (int i = 0, len = _segments.size(); i < len; ++i) {
char[] curr = _segments.get(i);
int currLen = curr.length;
System.arraycopy(curr, 0, result, offset, currLen);
offset += currLen;
}
}
System.arraycopy(_currentSegment, 0, result, offset, _currentSize);
return result;
}
private char[] carr(int len) { return new char[len]; }
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>package com.fasterxml.jackson.core.io;
import java.io.*;
public final class UTF8Writer extends Writer
{
final static int SURR1_FIRST = 0xD800;
final static int SURR1_LAST = 0xDBFF;
final static int SURR2_FIRST = 0xDC00;
final static int SURR2_LAST = 0xDFFF;
final private IOContext _context;
private OutputStream _out;
private byte[] _outBuffer;
final private int _outBufferEnd;
private int _outPtr;
/**
* When outputting chars from BMP, surrogate pairs need to be coalesced.
* To do this, both pairs must be known first; and since it is possible
* pairs may be split, we need temporary storage for the first half
*/
private int _surrogate;
public UTF8Writer(IOContext ctxt, OutputStream out)
{
_context = ctxt;
_out = out;
_outBuffer = ctxt.allocWriteEncodingBuffer();
/* Max. expansion for a single char (in unmodified UTF-8) is
* 4 bytes (or 3 depending on how you view it -- 4 when recombining
* surrogate pairs)
*/
_outBufferEnd = _outBuffer.length - 4;
_outPtr = 0;
}
@Override
public Writer append(char c)
throws IOException
{
write(c);
return this;
}
@Override
public void close()
throws IOException
{
if (_out != null) {
if (_outPtr > 0) {
_out.write(_outBuffer, 0, _outPtr);
_outPtr = 0;
}
OutputStream out = _out;
_out = null;
byte[] buf = _outBuffer;
if (buf != null) {
_outBuffer = null;
_context.releaseWriteEncodingBuffer(buf);
}
out.close();
/* Let's 'flush' orphan surrogate, no matter what; but only
* after cleanly closing everything else.
*/
int code = _surrogate;
_surrogate = 0;
if (code > 0) {
illegalSurrogate(code);
}
}
}
@Override
public void flush()
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
throws IOException
{
if (_out != null) {
if (_outPtr > 0) {
_out.write(_outBuffer, 0, _outPtr);
_outPtr = 0;
}
_out.flush();
}
}
@Override
public void write(char[] cbuf)
throws IOException
{
write(cbuf, 0, cbuf.length);
}
@Override
public void write(char[] cbuf, int off, int len)
throws IOException
{
if (len < 2) {
if (len == 1) {
write(cbuf[off]);
}
return;
}
// First: do we have a leftover surrogate to deal with?
if (_surrogate > 0) {
char second = cbuf[off++];
--len;
write(convertSurrogate(second));
// will have at least one more char
}
int outPtr = _outPtr;
byte[] outBuf = _outBuffer;
int outBufLast = _outBufferEnd; // has 4 'spare' bytes
// All right; can just loop it nice and easy now:
len += off; // len will now be the end of input buffer
output_loop:
for (; off < len; ) {
/* First, let's ensure we can output at least 4 bytes
* (longest UTF-8 encoded codepoint):
*/
if (outPtr >= outBufLast) {
_out.write(outBuf, 0, outPtr);
outPtr = 0;
}
int c = cbuf[off++];
// And then see if we have an Ascii char:
if (c < 0x80) { // If so, can do a tight inner loop:
outBuf[outPtr++] = (byte)c;
// Let's calc how many ascii chars we can copy at most:
int maxInCount = (len - off);
int maxOutCount = (outBufLast - outPtr);
if (maxInCount > maxOutCount) {
maxInCount = maxOutCount;
}
maxInCount += off;
ascii_loop:
while (true) {
if (off >= maxInCount) { // done with max. ascii seq
continue output_loop;
}
c = cbuf
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> str) throws IOException
{
write(str, 0, str.length());
}
@Override
public void write(String str, int off, int len) throws IOException
{
if (len < 2) {
if (len == 1) {
write(str.charAt(off));
}
return;
}
// First: do we have a leftover surrogate to deal with?
if (_surrogate > 0) {
char second = str.charAt(off++);
--len;
write(convertSurrogate(second));
// will have at least one more char (case of 1 char was checked earlier on)
}
int outPtr = _outPtr;
byte[] outBuf = _outBuffer;
int outBufLast = _outBufferEnd; // has 4 'spare' bytes
// All right; can just loop it nice and easy now:
len += off; // len will now be the end of input buffer
output_loop:
for (; off < len; ) {
/* First, let's ensure we can output at least 4 bytes
* (longest UTF-8 encoded codepoint):
*/
if (outPtr >= outBufLast) {
_out.write(outBuf, 0, outPtr);
outPtr = 0;
}
int c = str.charAt(off++);
// And then see if we have an Ascii char:
if (c < 0x80) { // If so, can do a tight inner loop:
outBuf[outPtr++] = (byte)c;
// Let's calc how many ascii chars we can copy at most:
int maxInCount = (len - off);
int maxOutCount = (outBufLast - outPtr);
if (maxInCount > maxOutCount) {
maxInCount = maxOutCount;
}
maxInCount += off;
ascii_loop:
while (true) {
if (off >= maxInCount) { // done with max. ascii seq
continue output_loop;
}
c = str.charAt(off++);
if (c >= 0x80) {
break ascii_loop;
}
outBuf[outPtr++] = (byte) c;
}
}
// Nope, multi-byte:
if (c < 0x800
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>
// Then possible leading space
int ch = skipSpace(acc, b);
if (ch < 0) {
return MatchStrength.INCONCLUSIVE;
}
// First, let's see if it looks like a structured type:
if (ch == '{') { // JSON object?
// Ideally we need to find either double-quote or closing bracket
ch = skipSpace(acc);
if (ch < 0) {
return MatchStrength.INCONCLUSIVE;
}
if (ch == '"' || ch == '}') {
return MatchStrength.SOLID_MATCH;
}
// ... should we allow non-standard? Let's not yet... can add if need be
return MatchStrength.NO_MATCH;
}
MatchStrength strength;
if (ch == '[') {
ch = skipSpace(acc);
if (ch < 0) {
return MatchStrength.INCONCLUSIVE;
}
// closing brackets is easy; but for now, let's also accept opening...
if (ch == ']' || ch == '[') {
return MatchStrength.SOLID_MATCH;
}
return MatchStrength.SOLID_MATCH;
} else {
// plain old value is not very convincing...
strength = MatchStrength.WEAK_MATCH;
}
if (ch == '"') { // string value
return strength;
}
if (ch <= '9' && ch >= '0') { // number
return strength;
}
if (ch == '-') { // negative number
ch = skipSpace(acc);
if (ch < 0) {
return MatchStrength.INCONCLUSIVE;
}
return (ch <= '9' && ch >= '0') ? strength : MatchStrength.NO_MATCH;
}
// or one of literals
if (ch == 'n') { // null
return tryMatch(acc, "ull", strength);
}
if (ch == 't') { // true
return tryMatch(acc, "rue", strength);
}
if (ch == 'f') { // false
return tryMatch(acc, "alse", strength);
}
return MatchStrength.NO_MATCH;
}
private static MatchStrength tryMatch(InputAccessor acc, String matchStr, MatchStrength fullMatchStrength)
throws IOException
{
for (int i = 0, len = matchStr.length
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> = false;
} else { // nope, not UTF-16
return false;
}
// Not BOM (just regular content), nothing to skip past:
//_inputPtr += 2;
_bytesPerChar = 2;
return true;
}
/*
/**********************************************************
/* Internal methods, problem reporting
/**********************************************************
*/
private void reportWeirdUCS4(String type) throws IOException {
throw new CharConversionException("Unsupported UCS-4 endianness ("+type+") detected");
}
/*
/**********************************************************
/* Internal methods, raw input access
/**********************************************************
*/
protected boolean ensureLoaded(int minimum) throws IOException {
/* Let's assume here buffer has enough room -- this will always
* be true for the limited used this method gets
*/
int gotten = (_inputEnd - _inputPtr);
while (gotten < minimum) {
int count;
if (_in == null) { // block source
count = -1;
} else {
count = _in.read(_inputBuffer, _inputEnd, _inputBuffer.length - _inputEnd);
}
if (count < 1) {
return false;
}
_inputEnd += count;
gotten += count;
}
return true;
}
}
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> = null;
} else {
_serialized = token;
_serializedChars = token.toCharArray();
// It's all in ascii, can just case...
int len = _serializedChars.length;
_serializedBytes = new byte[len];
for (int i = 0; i < len; ++i) {
_serializedBytes[i] = (byte) _serializedChars[i];
}
}
_id = id;
_isBoolean = (id == JsonTokenId.ID_FALSE || id == JsonTokenId.ID_TRUE);
_isNumber = (id == JsonTokenId.ID_NUMBER_INT || id == JsonTokenId.ID_NUMBER_FLOAT);
_isStructStart = (id == JsonTokenId.ID_START_OBJECT || id == JsonTokenId.ID_START_ARRAY);
_isStructEnd = (id == JsonTokenId.ID_END_OBJECT || id == JsonTokenId.ID_END_ARRAY);
_isScalar = !_isStructStart && !_isStructEnd
&& (id != JsonTokenId.ID_FIELD_NAME)
&& (id != JsonTokenId.ID_NOT_AVAILABLE);
}
public final int id() { return _id; }
public final String asString() { return _serialized; }
public final char[] asCharArray() { return _serializedChars; }
public final byte[] asByteArray() { return _serializedBytes; }
public final boolean isNumeric() { return _isNumber; }
/**
* Accessor that is functionally equivalent to:
* <code>
* this == JsonToken.START_OBJECT || this == JsonToken.START_ARRAY
* </code>
*
* @since 2.3
*/
public final boolean isStructStart() { return _isStructStart; }
/**
* Accessor that is functionally equivalent to:
* <code>
* this == JsonToken.END_OBJECT || this == JsonToken.END_ARRAY
* </code>
*
* @since 2.3
*/
public final boolean isStructEnd() { return _isStructEnd; }
/**
* Method that can be used to check whether this token represents
* a valid non-structured value. This means all tokens other than
* Object/Array start/end markers all field names.
*/
public final boolean isScalarValue() { return _is
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>12.9", "-999.0",
"2.5e+5", "9e4", "-12e-3", "0.25",
};
for (int input = 0; input < 2; ++input) {
for (int i = 0; i < INPUTS.length; ++i) {
// First in array
String STR = INPUTS[i];
double EXP_D = Double.parseDouble(STR);
String DOC = "["+STR+"]";
JsonParser jp;
if (input == 0) {
jp = createParserUsingStream(DOC, "UTF-8");
} else {
jp = FACTORY.createParser(DOC);
}
assertToken(JsonToken.START_ARRAY, jp.nextToken());
assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
assertEquals(STR, jp.getText());
assertEquals(EXP_D, jp.getDoubleValue());
assertToken(JsonToken.END_ARRAY, jp.nextToken());
assertNull(jp.nextToken());
jp.close();
// then outside
if (input == 0) {
jp = createParserUsingStream(STR, "UTF-8");
} else {
jp = FACTORY.createParser(STR);
}
JsonToken t = null;
try {
t = jp.nextToken();
} catch (Exception e) {
throw new Exception("Failed to parse input '"+STR+"' (parser of type "+jp.getClass().getSimpleName()+")", e);
}
assertToken(JsonToken.VALUE_NUMBER_FLOAT, t);
assertEquals(STR, jp.getText());
assertNull(jp.nextToken());
jp.close();
}
}
}
public void testNumbers() throws Exception
{
final String DOC = "[ -13, 8100200300, 13.5, 0.00010, -2.033 ]";
for (int input = 0; input < 2; ++input) {
JsonParser jp;
if (input == 0) {
jp = createParserUsingStream(DOC, "UTF-8");
} else {
jp = FACTORY.createParser(DOC);
}
assertToken(JsonToken.START_ARRAY, jp.nextToken());
assertToken(
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>input == 0) {
jp = createParserUsingStream(DOC_BELOW, "UTF-8");
} else {
jp = FACTORY.createParser(DOC_BELOW);
}
jp.nextToken();
try {
long x = jp.getLongValue();
fail("Expected an exception for underflow (input "+jp.getText()+"): instead, got long value: "+x);
} catch (JsonParseException e) {
verifyException(e, "out of range of long");
}
jp.close();
if (input == 0) {
jp = createParserUsingStream(DOC_ABOVE, "UTF-8");
} else {
jp = createParserUsingReader(DOC_ABOVE);
}
jp.nextToken();
try {
long x = jp.getLongValue();
fail("Expected an exception for underflow (input "+jp.getText()+"): instead, got long value: "+x);
} catch (JsonParseException e) {
verifyException(e, "out of range of long");
}
jp.close();
}
}
/**
* Method that tries to test that number parsing works in cases where
* input is split between buffer boundaries.
*/
public void testParsingOfLongerSequences()
throws Exception
{
double[] values = new double[] { 0.01, -10.5, 2.1e9, 4.0e-8 };
StringBuilder sb = new StringBuilder();
for (int i = 0; i < values.length; ++i) {
if (i > 0) {
sb.append(',');
}
sb.append(values[i]);
}
String segment = sb.toString();
int COUNT = 1000;
sb = new StringBuilder(COUNT * segment.length() + 20);
sb.append("[");
for (int i = 0; i < COUNT; ++i) {
if (i > 0) {
sb.append(',');
}
sb.append(segment);
sb.append('\n');
// let's add somewhat arbitrary number of spaces
int x = (i & 3);
if (i > 300) {
x += i % 5;
}
while (--x > 0) {
sb.append(' ');
}
}
sb.append
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>LongNumbers(f, DOC, false);
_testIssue160LongNumbers(f, DOC, true);
}
private void _testIssue160LongNumbers(JsonFactory f, String doc, boolean useStream) throws Exception
{
JsonParser jp = useStream
? FACTORY.createParser(doc.getBytes("UTF-8"))
: FACTORY.createParser(doc);
assertToken(JsonToken.VALUE_NUMBER_INT, jp.nextToken());
BigInteger v = jp.getBigIntegerValue();
assertNull(jp.nextToken());
assertEquals(doc, v.toString());
}
// for [jackson-core#181]
/**
* Method that tries to test that number parsing works in cases where
* input is split between buffer boundaries.
*/
public void testParsingOfLongerSequencesWithNonNumeric() throws Exception
{
JsonFactory factory = new JsonFactory();
factory.enable(JsonParser.Feature.ALLOW_NON_NUMERIC_NUMBERS);
double[] values = new double[] {
0.01, -10.5, 2.1e9, 4.0e-8,
Double.NaN, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY
};
for (int i = 0; i < values.length; ++i) {
int COUNT = 4096;
// Don't see the failure with a multiple of 1
int VCOUNT = 2 * COUNT;
String arrayJson = toJsonArray(values[i], VCOUNT);
StringBuilder sb = new StringBuilder(COUNT + arrayJson.length() + 20);
for (int j = 0; j < COUNT; ++j) {
sb.append(' ');
}
sb.append(arrayJson);
String DOC = sb.toString();
for (int input = 0; input < 2; ++input) {
JsonParser jp;
if (input == 0) {
jp = createParserUsingStream(factory, DOC, "UTF-8");
} else {
jp = factory.createParser(DOC);
}
assertToken(JsonToken.START_ARRAY, jp.nextToken());
for (int j = 0; j < VCOUNT; ++j) {
assertToken(JsonToken.VALUE_NUMBER_FLOAT, jp.nextToken());
assertEquals(values[i], jp.getDouble
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>package com.fasterxml.jackson.core.io;
import java.io.*;
/**
* Simple {@link InputStream} implementation that is used to "unwind" some
* data previously read from an input stream; so that as long as some of
* that data remains, it's returned; but as long as it's read, we'll
* just use data from the underlying original stream.
* This is similar to {@link java.io.PushbackInputStream}, but here there's
* only one implicit pushback, when instance is constructed.
*/
public final class MergedStream extends InputStream
{
final private IOContext _ctxt;
final private InputStream _in;
private byte[] _b;
private int _ptr;
final private int _end;
public MergedStream(IOContext ctxt, InputStream in, byte[] buf, int start, int end) {
_ctxt = ctxt;
_in = in;
_b = buf;
_ptr = start;
_end = end;
}
@Override
public int available() throws IOException {
if (_b != null) {
return _end - _ptr;
}
return _in.available();
}
@Override public void close() throws IOException {
_free();
_in.close();
}
@Override public void mark(int readlimit) {
if (_b == null) { _in.mark(readlimit); }
}
@Override public boolean markSupported() {
// Only supports marks past the initial rewindable section...
return (_b == null) && _in.markSupported();
}
@Override public int read() throws IOException {
if (_b != null) {
int c = _b[_ptr++] & 0xFF;
if (_ptr >= _end) {
_free();
}
return c;
}
return _in.read();
}
@Override public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
@Override
public int read(byte[] b, int off, int len) throws IOException {
if (_b != null) {
int avail = _end - _ptr;
if (len > avail) {
len = avail;
}
System.arraycopy(_b, _ptr, b, off, len);
_ptr += len;
if (_ptr >= _end) {
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>() {
this(4, 4);
}
/**
* Alternate constructor to be used by sub-classes, to allow customization
* of number of low-level buffers in use.
*
* @since 2.4
*/
protected BufferRecycler(int bbCount, int cbCount) {
_byteBuffers = new byte[bbCount][];
_charBuffers = new char[cbCount][];
}
/*
/**********************************************************
/* Public API, byte buffers
/**********************************************************
*/
/**
* @param ix One of <code>READ_IO_BUFFER</code> constants.
*/
public final byte[] allocByteBuffer(int ix) {
return allocByteBuffer(ix, 0);
}
public byte[] allocByteBuffer(int ix, int minSize) {
final int DEF_SIZE = byteBufferLength(ix);
if (minSize < DEF_SIZE) {
minSize = DEF_SIZE;
}
byte[] buffer = _byteBuffers[ix];
if (buffer == null || buffer.length < minSize) {
buffer = balloc(minSize);
} else {
_byteBuffers[ix] = null;
}
return buffer;
}
public final void releaseByteBuffer(int ix, byte[] buffer) {
_byteBuffers[ix] = buffer;
}
/*
/**********************************************************
/* Public API, char buffers
/**********************************************************
*/
public final char[] allocCharBuffer(int ix) {
return allocCharBuffer(ix, 0);
}
public char[] allocCharBuffer(int ix, int minSize) {
final int DEF_SIZE = charBufferLength(ix);
if (minSize < DEF_SIZE) {
minSize = DEF_SIZE;
}
char[] buffer = _charBuffers[ix];
if (buffer == null || buffer.length < minSize) {
buffer = calloc(minSize);
} else {
_charBuffers[ix] = null;
}
return buffer;
}
public void releaseCharBuffer(int ix, char[] buffer) {
_charBuffers[ix] = buffer;
}
/*
/**********************************************************
/* Overridable helper methods
/**********************************************************
*/
protected int byteBufferLength(int ix) {
return BYTE_BUFFER_LENGTHS[ix];
}
protected int charBufferLength(int ix
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> once per line.
*/
protected int _currInputRowStart;
/*
/**********************************************************
/* Information about starting location of event
/* Reader is pointing to; updated on-demand
/**********************************************************
*/
// // // Location info at point when current token was started
/**
* Total number of bytes/characters read before start of current token.
* For big (gigabyte-sized) sizes are possible, needs to be long,
* unlike pointers and sizes related to in-memory buffers.
*/
protected long _tokenInputTotal;
/**
* Input row on which current token starts, 1-based
*/
protected int _tokenInputRow = 1;
/**
* Column on input row that current token starts; 0-based (although
* in the end it'll be converted to 1-based)
*/
protected int _tokenInputCol;
/*
/**********************************************************
/* Parsing state
/**********************************************************
*/
/**
* Information about parser context, context in which
* the next token is to be parsed (root, array, object).
*/
protected JsonReadContext _parsingContext;
/**
* Secondary token related to the next token after current one;
* used if its type is known. This may be value token that
* follows FIELD_NAME, for example.
*/
protected JsonToken _nextToken;
/*
/**********************************************************
/* Buffer(s) for local name(s) and text content
/**********************************************************
*/
/**
* Buffer that contains contents of String values, including
* field names if necessary (name split across boundary,
* contains escape sequence, or access needed to char array)
*/
protected final TextBuffer _textBuffer;
/**
* Temporary buffer that is needed if field name is accessed
* using {@link #getTextCharacters} method (instead of String
* returning alternatives)
*/
protected char[] _nameCopyBuffer;
/**
* Flag set to indicate whether the field name is available
* from the name copy buffer or not (in addition to its String
* representation being available via read context)
*/
protected boolean _nameCopied;
/**
* ByteArrayBuilder is needed if 'getBinaryValue' is called. If so,
* we better reuse it for remainder of content.
*/
protected ByteArrayBuilder _byteArrayBuilder;
/**
* We will hold on to decoded binary data, for duration of
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>';
final protected static char CHAR_NULL = '\0';
// Numeric value holders: multiple fields used for
// for efficiency
/**
* Bitfield that indicates which numeric representations
* have been calculated for the current type
*/
protected int _numTypesValid = NR_UNKNOWN;
// First primitives
protected int _numberInt;
protected long _numberLong;
protected double _numberDouble;
// And then object types
protected BigInteger _numberBigInt;
protected BigDecimal _numberBigDecimal;
// And then other information about value itself
/**
* Flag that indicates whether numeric value has a negative
* value. That is, whether its textual representation starts
* with minus character.
*/
protected boolean _numberNegative;
/**
* Length of integer part of the number, in characters
*/
protected int _intLength;
/**
* Length of the fractional part (not including decimal
* point or exponent), in characters.
* Not used for pure integer values.
*/
protected int _fractLength;
/**
* Length of the exponent part of the number, if any, not
* including 'e' marker or sign, just digits.
* Not used for pure integer values.
*/
protected int _expLength;
/*
/**********************************************************
/* Life-cycle
/**********************************************************
*/
protected ParserBase(IOContext ctxt, int features) {
super(features);
_ioContext = ctxt;
_textBuffer = ctxt.constructTextBuffer();
DupDetector dups = Feature.STRICT_DUPLICATE_DETECTION.enabledIn(features)
? DupDetector.rootDetector(this) : null;
_parsingContext = JsonReadContext.createRootContext(dups);
}
@Override public Version version() { return PackageVersion.VERSION; }
@Override
public Object getCurrentValue() {
return _parsingContext.getCurrentValue();
}
@Override
public void setCurrentValue(Object v) {
_parsingContext.setCurrentValue(v);
}
/*
/**********************************************************
/* Overrides for Feature handling
/**********************************************************
*/
@Override
public JsonParser enable(Feature f) {
_features |= f.getMask();
if (f == Feature.STRICT_DUPLICATE_DETECTION) { // enabling dup detection?
if (_parsingContext.getDupDetector() == null) { // but only if disabled currently
_
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>Override
public boolean hasTextCharacters() {
if (_currToken == JsonToken.VALUE_STRING) { return true; } // usually true
if (_currToken == JsonToken.FIELD_NAME) { return _nameCopied; }
return false;
}
// No embedded objects with base impl...
@Override public Object getEmbeddedObject() throws IOException { return null; }
@SuppressWarnings("resource")
@Override // since 2.7
public byte[] getBinaryValue(Base64Variant variant) throws IOException
{
if (_binaryValue == null) {
if (_currToken != JsonToken.VALUE_STRING) {
_reportError("Current token ("+_currToken+") not VALUE_STRING, can not access as binary");
}
ByteArrayBuilder builder = _getByteArrayBuilder();
_decodeBase64(getText(), builder, variant);
_binaryValue = builder.toByteArray();
}
return _binaryValue;
}
/*
/**********************************************************
/* Public low-level accessors
/**********************************************************
*/
public long getTokenCharacterOffset() { return _tokenInputTotal; }
public int getTokenLineNr() { return _tokenInputRow; }
public int getTokenColumnNr() {
// note: value of -1 means "not available"; otherwise convert from 0-based to 1-based
int col = _tokenInputCol;
return (col < 0) ? col : (col + 1);
}
/*
/**********************************************************
/* Low-level reading, other
/**********************************************************
*/
protected final void loadMoreGuaranteed() throws IOException {
if (!loadMore()) { _reportInvalidEOF(); }
}
/*
/**********************************************************
/* Abstract methods needed from sub-classes
/**********************************************************
*/
protected abstract boolean loadMore() throws IOException;
protected abstract void _finishString() throws IOException;
protected abstract void _closeInput() throws IOException;
/*
/**********************************************************
/* Low-level reading, other
/**********************************************************
*/
/**
* Method called to release internal buffers owned by the base
* reader. This may be called along with {@link #_closeInput} (for
* example, when explicitly closing this reader instance), or
* separately (if need be).
*/
protected void _releaseBuffers() throws IOException {
_textBuffer.releaseBuffers();
char[] buf = _nameCopyBuffer;
if (buf !=
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS>.VALUE_NUMBER_INT;
}
protected final JsonToken resetFloat(boolean negative, int intLen, int fractLen, int expLen)
{
_numberNegative = negative;
_intLength = intLen;
_fractLength = fractLen;
_expLength = expLen;
_numTypesValid = NR_UNKNOWN; // to force parsing
return JsonToken.VALUE_NUMBER_FLOAT;
}
protected final JsonToken resetAsNaN(String valueStr, double value)
{
_textBuffer.resetWithString(valueStr);
_numberDouble = value;
_numTypesValid = NR_DOUBLE;
return JsonToken.VALUE_NUMBER_FLOAT;
}
/*
/**********************************************************
/* Numeric accessors of public API
/**********************************************************
*/
@Override
public Number getNumberValue() throws IOException
{
if (_numTypesValid == NR_UNKNOWN) {
_parseNumericValue(NR_UNKNOWN); // will also check event type
}
// Separate types for int types
if (_currToken == JsonToken.VALUE_NUMBER_INT) {
if ((_numTypesValid & NR_INT) != 0) {
return _numberInt;
}
if ((_numTypesValid & NR_LONG) != 0) {
return _numberLong;
}
if ((_numTypesValid & NR_BIGINT) != 0) {
return _numberBigInt;
}
// Shouldn't get this far but if we do
return _numberBigDecimal;
}
/* And then floating point types. But here optimal type
* needs to be big decimal, to avoid losing any data?
*/
if ((_numTypesValid & NR_BIGDECIMAL) != 0) {
return _numberBigDecimal;
}
if ((_numTypesValid & NR_DOUBLE) == 0) { // sanity check
_throwInternal();
}
return _numberDouble;
}
@Override
public NumberType getNumberType() throws IOException
{
if (_numTypesValid == NR_UNKNOWN) {
_parseNumericValue(NR_UNKNOWN); // will also check event type
}
if (_currToken == JsonToken.VALUE_NUMBER_INT) {
if ((_numTypesValid & NR_INT) != 0) {
return NumberType.INT;
}
if ((_numTypesValid & NR_LONG) != 0) {
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> getDoubleValue() throws IOException
{
if ((_numTypesValid & NR_DOUBLE) == 0) {
if (_numTypesValid == NR_UNKNOWN) {
_parseNumericValue(NR_DOUBLE);
}
if ((_numTypesValid & NR_DOUBLE) == 0) {
convertNumberToDouble();
}
}
return _numberDouble;
}
@Override
public BigDecimal getDecimalValue() throws IOException
{
if ((_numTypesValid & NR_BIGDECIMAL) == 0) {
if (_numTypesValid == NR_UNKNOWN) {
_parseNumericValue(NR_BIGDECIMAL);
}
if ((_numTypesValid & NR_BIGDECIMAL) == 0) {
convertNumberToBigDecimal();
}
}
return _numberBigDecimal;
}
/*
/**********************************************************
/* Conversion from textual to numeric representation
/**********************************************************
*/
/**
* Method that will parse actual numeric value out of a syntactically
* valid number value. Type it will parse into depends on whether
* it is a floating point number, as well as its magnitude: smallest
* legal type (of ones available) is used for efficiency.
*
* @param expType Numeric type that we will immediately need, if any;
* mostly necessary to optimize handling of floating point numbers
*/
protected void _parseNumericValue(int expType) throws IOException
{
// Int or float?
if (_currToken == JsonToken.VALUE_NUMBER_INT) {
char[] buf = _textBuffer.getTextBuffer();
int offset = _textBuffer.getTextOffset();
int len = _intLength;
if (_numberNegative) {
++offset;
}
if (len <= 9) { // definitely fits in int
int i = NumberInput.parseInt(buf, offset, len);
_numberInt = _numberNegative ? -i : i;
_numTypesValid = NR_INT;
return;
}
if (len <= 18) { // definitely fits AND is easy to parse using 2 int parse calls
long l = NumberInput.parseLong(buf, offset, len);
if (_numberNegative) {
l = -l;
}
// [JACKSON-230] Could still fit in int, need to check
if (len == 10) {
if (_numberNegative) {
if (l >=
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> MIN_INT_L) {
_numberInt = (int) l;
_numTypesValid = NR_INT;
return;
}
} else {
if (l <= MAX_INT_L) {
_numberInt = (int) l;
_numTypesValid = NR_INT;
return;
}
}
}
_numberLong = l;
_numTypesValid = NR_LONG;
return;
}
_parseSlowInt(expType, buf, offset, len);
return;
}
if (_currToken == JsonToken.VALUE_NUMBER_FLOAT) {
_parseSlowFloat(expType);
return;
}
_reportError("Current token ("+_currToken+") not numeric, can not use numeric value accessors");
}
/**
* @since 2.6
*/
protected int _parseIntValue() throws IOException
{
// Inlined variant of: _parseNumericValue(NR_INT)
if (_currToken == JsonToken.VALUE_NUMBER_INT) {
char[] buf = _textBuffer.getTextBuffer();
int offset = _textBuffer.getTextOffset();
int len = _intLength;
if (_numberNegative) {
++offset;
}
if (len <= 9) {
int i = NumberInput.parseInt(buf, offset, len);
if (_numberNegative) {
i = -i;
}
_numberInt = i;
_numTypesValid = NR_INT;
return i;
}
}
_parseNumericValue(NR_INT);
if ((_numTypesValid & NR_INT) == 0) {
convertNumberToInt();
}
return _numberInt;
}
private void _parseSlowFloat(int expType) throws IOException
{
/* Nope: floating point. Here we need to be careful to get
* optimal parsing strategy: choice is between accurate but
* slow (BigDecimal) and lossy but fast (Double). For now
* let's only use BD when explicitly requested -- it can
* still be constructed correctly at any point since we do
* retain textual representation
*/
try {
if (expType == NR_BIGDECIMAL) {
_numberBigDecimal = _textBuffer.contentsAsDecimal();
_numTypesValid = NR_BIGDECIMAL;
} else {
// Otherwise double has to do
_numberDouble
JacksonCore, 19
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (outPtr >= outBuf.length) {
outBuf = _textBuffer.finishCurrentSegment();
outPtr = 0;
}
<CHANGEE>
<FILEE>
<FILEB>
outPtr = 0;
}
outBuf[outPtr++] = c;
if (_inputPtr >= _inputEnd && !loadMore()) {
// EOF is legal for main level int values
c = CHAR_NULL;
eof = true;
break int_loop;
}
c = _inputBuffer[_inputPtr++];
}
// Also, integer part is not optional
if (intLen == 0) {
return _handleInvalidNumberStart(c, neg);
}
int fractLen = 0;
// And then see if we get other parts
if (c == '.') { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = _inputBuffer[_inputPtr++];
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<FILEB>
if (ch < INT_0 || ch > INT_9) { // followed by non-number; retain one zero
return INT_0;
}
++_inputPtr; // skip previous zeroes
if (ch != INT_0) { // followed by other number; return
break;
}
}
}
return ch;
}
private final JsonToken _parseFloat(char[] outBuf, int outPtr, int c,
boolean negative, int integerPartLength) throws IOException
{
int fractLen = 0;
boolean eof = false;
// And then see if we get other parts
if (c == INT_PERIOD) { // yes, fraction
<CHANGES>
<CHANGEE>
outBuf[outPtr++] = (char) c;
fract_loop:
while (true) {
if (_inputPtr >= _inputEnd && !loadMore()) {
eof = true;
break fract_loop;
}
c = (int) _inputBuffer[_inputPtr++] & 0xFF;
if (c < INT_0 || c > INT_9) {
break fract_loop;
}
++fractLen;
<FILEE>
<SCANS> = _textBuffer.contentsAsDouble();
_numTypesValid = NR_DOUBLE;
}
} catch (NumberFormatException nex) {
// Can this ever occur? Due to overflow, maybe?
_wrapError("Malformed numeric value '"+_textBuffer.contentsAsString()+"'", nex);
}
}
private void _parseSlowInt(int expType, char[] buf, int offset, int len) throws IOException
{
String numStr = _textBuffer.contentsAsString();
try {
// [JACKSON-230] Some long cases still...
if (NumberInput.inLongRange(buf, offset, len, _numberNegative)) {
// Probably faster to construct a String, call parse, than to use BigInteger
_numberLong = Long.parseLong(numStr);
_numTypesValid = NR_LONG;
} else {
// nope, need the heavy guns... (rare case)
_numberBigInt = new BigInteger(numStr);
_numTypesValid = NR_BIGINT;
}
} catch (NumberFormatException nex) {
// Can this ever occur? Due to overflow, maybe?
_wrapError("Malformed numeric value '"+numStr+"'", nex);
}
}
/*
/**********************************************************
/* Numeric conversions
/**********************************************************
*/
protected void convertNumberToInt() throws IOException
{
// First, converting from long ought to be easy
if ((_numTypesValid & NR_LONG) != 0) {
// Let's verify it's lossless conversion by simple roundtrip
int result = (int) _numberLong;
if (((long) result) != _numberLong) {
_reportError("Numeric value ("+getText()+") out of range of int");
}
_numberInt = result;
} else if ((_numTypesValid & NR_BIGINT) != 0) {
if (BI_MIN_INT.compareTo(_numberBigInt) > 0
|| BI_MAX_INT.compareTo(_numberBigInt) < 0) {
reportOverflowInt();
}
_numberInt = _numberBigInt.intValue();
} else if ((_numTypesValid & NR_DOUBLE) != 0) {
// Need to check boundaries
if (_numberDouble < MIN_INT_D || _numberDouble > MAX_INT_D) {
reportOverflowInt();
}
_numberInt